Spring初始了解笔记
来源:互联网 发布:养生域名交易 编辑:程序博客网 时间:2024/05/10 06:24
1、spring依赖库
* SPRING_HOME/dist/spring.jar
* SPRING_HOME/lib/jakarta-commons/commons-logging.jar
* SPRING_HOME/lib/log4j/log4j-1.2.14.jar
2、拷贝spring配置文件到src下
3、拷贝log4j配置文件到src下
4、在UserManagerImpl中提供构造函数或setter方法,spring将实例化好的UserDao实现注入给我们
在Spring的配置文件applicationContext.xml中
<bean id="userDao4MySqlImpl" class="com.bjsxt.spring.dao.UserDao4MySqlImpl"/>
<bean id="userDao4OracleImpl" class="com.bjsxt.spring.dao.UserDao4OracleImpl"/>
<bean id="userManager" class="com.bjsxt.spring.manager.UserManagerImpl">
<!-- 构造方法注入
<constructor-arg ref="userDao4OracleImpl"/>
-->
<property name="userDao" ref="userDao4OracleImpl"/>
</bean>
解释:com.bjsxt.spring.manager.UserManagerImpl中有属性UserDao 且有set方法
而userDao4MySqlImpl、userDao4OracleImpl都实现了UserDao接口.在客户端进行测试时,用到
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
UserManager userManager = (UserManager)factory.getBean("userManager");//这里的userManager就是配置文件中某个的
id名字,其实就像List list=new ArrayList();实现接口,
userManager.save("张三", "123");
5、让spring管理我们的对象创建和依赖,必须在spring配置中进行定义
6、编写客户端
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
UserManager userManager = (UserManager)factory.getBean("userManager");
userManager.save("张三", "123");
System.out.println("asfgdg");
spring Ioc容器的关键点:
* 必须将被管理的对象定义到spring配置文件中
* 必须定义构造函数或setter方法,让spring将对象注入过来
////////////////////////////////////////
1、spring的普通属性注入
参见:spring文档3.3章节
在测试Spring的几种数据类型注入时,可以定义全局BeanFactory 然后重写setup方法,这样每次调用BeanFactory时,就不用赋值了。
而applicationContext-*.xml指的是applicationContext-为开始的xml文件,因为Spring默认配置文件时applicationContext.xml但是上述一
个文件不能满足大量数据需要配置的需求。所以相应的文件数量就会增加。一般就会根据功能进行定义名字。像applicationContext-
beans.xml,
applicationContext-editor.xml以及applicationContext-other.xml看一下名字就知道什么意思,后缀名是beans的就是实体Bean的配置了。
这样为后期的维护也起到很好的帮助。
private BeanFactory factory;
@Override
protected void setUp() throws Exception {
factory = new ClassPathXmlApplicationContext("applicationContext-*.xml");
}
什么是属性编辑器,作用?
* 自定义属性编辑器,spring配置文件中的字符串转换成相应的对象进行注入
spring已经有内置的属性编辑器,我们可以根据需求自己定义属性编辑器
* 如何定义属性编辑器?
* 继承PropertyEditorSupport类,覆写setAsText()方法,参见:UtilDatePropertyEditor.java
////////////////////////////////////////
public class UtilDatePropertyEditor extends PropertyEditorSupport {
private String format="yyyy-MM-dd";
@Override
public void setAsText(String text) throws IllegalArgumentException {
System.out.println("UtilDatePropertyEditor.saveAsText() -- text=" + text);
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
Date d = sdf.parse(text);
this.setValue(d);
} catch (ParseException e) {
e.printStackTrace();
}
}
public void setFormat(String format) {
this.format = format;
}
}
////////////////////////////////////////
* 将属性编辑器注册到spring中,参见:applicationContext-editor.xml
////////////////////////////////////////
<!-- 定义属性编辑器 -->
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean class="com.bjsxt.spring.UtilDatePropertyEditor">
<property name="format" value="yyyy-MM-dd"/>
</bean>
</entry>
</map>
</property>
</bean>
其中bean id="customEditorConfigurer"以及其下层的<property name="customEditors">都是一定的,没有变化。要将属性编辑器注册,只要
在<property name="customEditors">下加入类似的配置文件: <map>
<entry >
<bean class="">
<property name="" ></property>
</bean>
</entry>
</map>
其实这和struts中的转换器差不多。这里不再详解。
////////////////////////////////////////
几种Class的关系:
public class Bean2 {
private Bean3 bean3;
private Bean4 bean4;
private Bean5 bean5;
///////////////////////////////////////
依赖对象的注入方式,可以采用:
* ref属性
* <ref>标签
* 内部<bean>来定义
////////////////////////////////////////
配置文件:
<bean id="bean2" class="com.bjsxt.spring.Bean2">
<property name="bean3" ref="bean3"/>
<property name="bean4">
<ref bean="bean4"/>
</property>
<property name="bean5" ref="bean5"/>
</bean>
///////////////////////////////////////
内部<Bean>的定义:
<bean id="bean3" class="com.bjsxt.spring.Bean3">
<property name="id" value="1000"/>
<property name="name">
<value>Jack</value>
</property>
<property name="password" value="123"/>
</bean>
<bean id="bean4" class="com.bjsxt.spring.Bean4">
<property name="id" value="1000"/>
<property name="name" value="Jack"/>
</bean>
<bean id="bean5" class="com.bjsxt.spring.Bean5">
<property name="age" value="20"/>
</bean>
////////////////////////////////////////
如何将公共的注入定义描述出来?
* 通过<bean>标签定义公共的属性,指定abstract=true
////////////////////////////////////////
<bean id="beanAbstract" abstract="true">
<property name="id" value="1000"/>
<property name="name" value="Jack"/>
</bean>
/////////////////////////////////////
* 具有相同属性的类在<bean>标签中指定其parent属性
Bean3和Bean4有公共相同的属性:int id;
String name;那么上面定义的父类标签abstract="true"同时初始了id 和name的值,这样只要Bean3和Bean4继承beanAbstract既可以。其实就
是继承吧。(现在的感觉就是)
下面是:
<bean id="bean3" class="com.bjsxt.spring.Bean3" parent="beanAbstract">
<property name="name" value="Tom"/>//也许有人会问,为什么要加此句,因为bean3还有一个属性,父类中没有,所以要
写。(对于初学者,这只是一种不需要解释的解释。)
<property name="password" value="123"/>
</bean>
<bean id="bean4" class="com.bjsxt.spring.Bean4" parent="beanAbstract"/>
///////////////////////////////////////
输出结果:
bean2.bean3.id=1000
bean2.bean3.name=Tom
bean2.bean3.password=123
bean2.bean4.id=1000
bean2.bean4.name=Jack
bean2.bean5.age=20
////////////////////////////////////////
下面介绍一下:abstract="true"的含义:abstract="true"
一个bean组件没有指定实现类,而是通过设置abstract="true"属性来组织spring 容器实例化组件
设置一个bean的属性abstract="true",表明这个bean只能作为其他bean的父bean使用,不能直接被实例化。
////////////////////////////////////////
下面介绍一下Spring Bean的作用域:
spring Bean的作用域:
scope可以取值:
* singleton:每次调用getBean的时候返回相同的实例,这时默认情况。
* prototype:每次调用getBean的时候返回不同的实例
///////////////////////////////////////
配置文件:
<!--
<bean id="bean1" class="com.bjsxt.spring.Bean1" scope="singleton"/>
-->
<bean id="bean1" class="com.bjsxt.spring.Bean1" scope="prototype"/>
////////////////////////////////////////
测试:
Bean1 bean11 = (Bean1)factory.getBean("bean1");
Bean1 bean12 = (Bean1)factory.getBean("bean1");
if (bean11 == bean12) {
System.out.println("bean11==bean12");
}else {
System.out.println("bean11!=bean12");
}
配置文件不同,则结果就会不同。
////////////////////////////////////////
下面介绍一下:自动装配问题:
1、根据名称自动装配;
首先:在<beans xmlns=""
最后面加上+
default-autowire="byName"即可
>
然后:配置<bean>时,不需要臃余的配置:将原来的<!--
<bean id="bean2" class="com.bjsxt.spring.Bean2">
<property name="bean3" ref="bean3"/>
<property name="bean4">
<ref bean="bean4"/>
</property>
<property name="bean5" ref="bean5"/>
</bean>
-->
改为:<bean id="bean2" class="com.bjsxt.spring.Bean2"/>
即可。
但是有一点必须记住其中的id的值就是
在类Bean2中:public class Bean2 {
private Bean3 bean3;
private Bean4 bean4;
private Bean5 bean5;
如果根据bean2调用bean3,bean4,bean4,那么配置文件怎么写呢?
首先,则依次定义三个bean 其中id的值必须为Bean2中的set,get后面的字符串,其实就是对应的bean3,bean4,bean5如果不这样定义,那么
根据bean2得到另外三个,就会出错。因为Bean2 bean2 = (Bean2)factory.getBean("bean2");
bean2.getBean3().getId()
在类Bean2中找不到相应的关联对象。
但是,其中的Bean2的<bean>id配置可以随意,因为Bean2是通过标签得到,而其他是通过类之间的关系得到。
2、根据类型自动装配;
只要将上述的default-autowire="byName"改为default-autowire="byType"即可,
那么像bean3、bean4、bean5可以为任意值,即不用与类Bean2中的名字一直,所以id的值可以为任意的。因为它会根据类型进行寻找。
我感觉default-autowire="byType"一般加在为引导bean定义的文件的页面中的。即在配置Bean2标签 <bean id="bean2"
class="com.bjsxt.spring.Bean2"/>在同一个页面,否则就会出错。即有谁引导,就定义在谁那里。(有点方言色彩。不好意思!)。
////////////////////////////////////////
下面介绍一下:动态代理:
要继承:java.lang.reflect.InvocationHandler;
public class SecurityHandler implements InvocationHandler {
private Object targetObject;
public Object newPoxy(Object targetObject){
this.targetObject=targetObject;
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),
this);
}
//下面的方法是该类继承InvocationHandler时,自动生成的,然后自己在重写。
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
checkSecurity();
Object ret=null;
try {
ret=method.invoke(this.targetObject, args);//这句话的意思可能就是返回对象时,就会自动加载
} catch (RuntimeException e) {
e.printStackTrace();
throw new java.lang.RuntimeException(e);
}
return ret;
}
////////////////////////////////////////
客户端测试:
public static void main(String[] args) {
SecurityHandler handler=new SecurityHandler();
UserManager usermanager=(UserManager)handler.newPoxy(new UserManagerImpl()); // UserManagerImpl是UserManager
接口的实现。
usermanager.addUser("w", "ewer");//调用该方法时,会自动调用checkSecurity()方法,
}
////////////////////////////////////////
输出结果:----------checkSecurity()---------------
-------UserManagerImpl.addUser()----------
///////////////////////////////////////
spring对AOP的只是(采用Annotation的方式)
1、spring依赖库
* SPRING_HOME/dist/spring.jar
* SPRING_HOME/lib/jakarta-commons/commons-logging.jar
* SPRING_HOME/lib/log4j/log4j-1.2.14.jar
* SPRING_HOME/lib/aspectj/*.jar
2、采用Aspect定义切面
2、在Aspect定义Pointcut和Advice
4、启用AspectJ对Annotation的支持并且将Aspect类和目标对象配置到Ioc容器中
注意:在这种方法定义中,切入点的方法是不被执行的,它存在的目的仅仅是为了重用切入点
即Advice中通过方法名引用这个切人点
AOP:
* Cross cutting concern
* Aspect
* Advice
* Pointcut
* Joinpoint
* Weave
* Target Object
* Proxy
* Introduction
////////////////////////////////////////
文件配置:首先在ApplicationContext.xml文件中加入:
<aop:aspectj-autoproxy/>
<bean id="securityHandler" class="com.bjsxt.spring.SecurityHandler"/>
<bean id="userManager" class="com.bjsxt.spring.UserManagerImpl"/>
其中的<bean>定义是,在用到AOP的类,其中UserManager.java只是个接口,不用配了。
//////////////////////////////////////
其中SecurityHandler.java
的主要代码:
@Aspect
public class SecurityHandler {
/**
* 定义Pointcut,Pointcut的名称就是allAddMethod,此方法不能有返回值和参数,该方法只是一个
* 标识
*
* Pointcut的内容是一个表达式,描述那些对象的那些方法(订阅Joinpoint)
*/
@Pointcut("execution(* add*(..)) || execution(* del*(..))")
private void allAddMethod(){};
/**
* 定义Advice,标识在那个切入点何处织入此方法
*/
@After("allAddMethod()")//在方法后加上checkSecurity()执行
//@Before("allAddMethod()")
private void checkSecurity() {
System.out.println("----------checkSecurity()---------------");
}
}这里的意思是,在调用某某对象的add**()和del**()方法时,会自动调用checkSecurity()方法。
///////////////////////////////////////
////////////////////////////////////////
下面介绍:静态配置文件方式实现AOP:
spring对AOP的只是(采用配置文件的方式)
1、spring依赖库
* SPRING_HOME/dist/spring.jar
* SPRING_HOME/lib/jakarta-commons/commons-logging.jar
* SPRING_HOME/lib/log4j/log4j-1.2.14.jar
* SPRING_HOME/lib/aspectj/*.jar
2、配置如下
<bean id="securityHandler" class="com.bjsxt.spring.SecurityHandler"/>
<bean id="userManager" class="com.bjsxt.spring.UserManagerImpl"/>
<aop:config>
<aop:aspect id="security" ref="securityHandler">
<aop:pointcut id="allAddMethod" expression="execution(* com.bjsxt.spring.UserManagerImpl.add*(..))"/>
/*只是实现以add开始的方法。
要是实现类中的所用的方法,则采用
<aop:pointcut id="allAddMethod" expression="execution(* com.bjsxt.spring.UserManagerImpl.*(..))"/>
同时不用加上这句:<aop:aspectj-autoproxy/>
*/
<aop:before method="checkSecurity" pointcut-ref="allAddMethod"/>
</aop:aspect>
</aop:config>
////////////////////////////////////////
其中:public class SecurityHandler {
private void checkSecurity() {
System.out.println("----------checkSecurity()---------------");
}
////////////////////////////////////////
spring对AOP的支持
Aspect默认情况下不用实现接口,但对于目标对象(UserManagerImpl.java),在默认情况下必须实现接口
如果没有实现接口必须引入CGLIB库
//客户端代码:
public static void main(String[] args) {
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
UserManager userManager = (UserManager)factory.getBean("userManager");
userManager.addUser("张三", "123");
//userManager.deleteUser(1);
}
/////////////////////////////////////////
我们可以通过Advice中添加一个JoinPoint参数,这个值会由spring自动传入,从JoinPoint中可以取得
参数值、方法名等等
public class SecurityHandler {
private void checkSecurity(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
for (int i=0; i<args.length; i++) {
System.out.println(args[i]);
}
System.out.println(joinPoint.getSignature().getName());
System.out.println("----------checkSecurity()---------------");
}
}
////////////////////////////////////////
其中applicationContext.xml
<bean id="securityHandler" class="com.bjsxt.spring.SecurityHandler"/>
<bean id="userManager" class="com.bjsxt.spring.UserManagerImpl"/>
<aop:config>
<aop:aspect id="security" ref="securityHandler">
<aop:pointcut id="allAddMethod" expression="execution(* com.bjsxt.spring.UserManagerImpl.add*(..))"/>
<aop:before method="checkSecurity" pointcut-ref="allAddMethod"/>
</aop:aspect>
</aop:config>
////////////////////////////////////////
////////////////////////////////////////spring对AOP的支持
1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换
如何强制使用CGLIB实现AOP?
* 添加CGLIB库,SPRING_HOME/cglib/*.jar
* 在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
JDK动态代理和CGLIB字节码生成的区别?
* JDK动态代理只能对实现了接口的类生成代理,而不能针对类
* CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final
////////////////////////////////////////
采用编程式事务
1、getCurrentSession()与openSession()的区别?
* 采用getCurrentSession()创建的session会绑定到当前线程中,而采用openSession()
创建的session则不会
* 采用getCurrentSession()创建的session在commit或rollback时会自动关闭,而采用openSession()
创建的session必须手动关闭
2、使用getCurrentSession()需要在hibernate.cfg.xml文件中加入如下配置:
* 如果使用的是本地事务(jdbc事务)
<property name="hibernate.current_session_context_class">thread</property>
* 如果使用的是全局事务(jta事务)
<property name="hibernate.current_session_context_class">jta</property>
////////////////////////////////////////三种事务差异
1、JDBC事务控制的局限性在一个数据库连接内,但是其使用简单。
2、JTA事务的功能强大,事务可以跨越多个数据库或多个DAO,使用也比较复杂。
3、容器事务,主要指的是J2EE应用服务器提供的事务管理,局限于EJB应用使用。
五、总结
事务控制是构建J2EE应用不可缺少的一部分,合理选择应用何种事务对整个应用系统来说至关重要。一般说来,在单个JDBC 连接连接的情况下
可以选择JDBC事务,在跨多个连接或者数据库情况下,需要选择使用JTA事务,如果用到了EJB,则可以考虑使用EJB容器事务。
////////////////////////////////////////
/////////////////////////////////////////
采用声明式事务
/////////////////////////////////////////////////
采用声明式事务:说明:为了便于管理,事务配置在applicationContext-common.xml中,
类的配置即<bean>配置在applicationContext-beans.xml中。
////////////////////////////////////////////////
1、声明式事务配置
* 配置SessionFactory
////////////////////////////////////////
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
////////////////////////////////////////
* 配置事务管理器
////////////////////////////////////////
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
////////////////////////////////////////
* 事务的传播特性
////////////////////////////////////////
<!-- 配置事务的传播特性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="del*" propagation="REQUIRED"/>
<tx:method name="modify*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>//这行的意思是其他方法是只读的形式,这样有利于性能的优化。而前
面增、减、改是可以请求事务的。
</tx:attributes>
</tx:advice>
////////////////////////////////////////
* 那些类那些方法使用事务
////////////////////////////////////////
<!-- 那些类的哪些方法参与事务 -->
<aop:config>
<aop:pointcut id="allManagerMethod" expression="execution(* com.bjsxt.usermgr.manager.*.*(..))"/>
<aop:advisor pointcut-ref="allManagerMethod" advice-ref="txAdvice"/>//这里的<aop:advisor>类似于Aspect
</aop:config>
////////////////////////////////////////
aop:advisor 和 aop:aspect的区别
advisor 策略 是通过切入点 找到符合条件的方法 再根据策略 进行相应方法的事务控制
而aop:aspect 是根据切入点找到符合条件的方法 然后再根据切面的类型(After、Before、Around)来适时的执行引入bean的方法
<aop:config>
<aop:aspect id="security" ref="securityHandler">
<aop:pointcut id="allAddMethod" expression="execution(* com.bjsxt.spring.UserManagerImpl.*(..))"/>
<aop:before method="checkSecurity" pointcut-ref="allAddMethod"/>
</aop:aspect>
</aop:config>
////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
"advisors"这个概念来自Spring1.2对AOP的支持,在AspectJ中是没有等价的概念。 advisor就像一个小的自包含的切面,这个切面只有一个通
知。 切面自身通过一个bean表示,并且必须实现一个通知接口, 在 第 7.3.2 节 “Spring里的通知类型” 中我们会讨论相应的接口。
Advisors可以很好的利用AspectJ切入点表达式。
Spring 2.0 通过 <aop:advisor> 元素来支持advisor 概念。 你将会发现它大多数情况下会和transactional advice一起使用,
transactional advice在Spring 2.0中有自己的命名空间。
////////////////////////////////////////
2、编写业务逻辑方法
针对这个小实验,实现的功能是在添加用户信息时,实现系统日志的记录,即用户表,日志表,涉及到两个表。
这对这些业务,设计了两个接口,一个是日志管理,一个是用户管理。
下面简单介绍一下日志管理接口实现:
////////////////////////////////////////public class LogManagerImpl extends HibernateDaoSupport implements LogManager {
public void addLog(Log log) {
this.getHibernateTemplate().save(log);
}
}
如果在Spring中用到Hibernate即在类中用到Hibernate,就必须继承HibernateDaoSupport
因为在类的方法中用到了getHibernateTemplate()方法。
////////////////////////////////////////
* 继承HibernateDaoSupport类,使用HibernateTemplate来持久化,HibernateTemplate是
Hibernate Session的轻量级封装
* 默认情况下运行期异常才会回滚(包括继承了RuntimeException子类),普通异常是不会滚的
* 编写业务逻辑方法时,最好将异常一直向上抛出,在表示层(struts)处理
* 关于事务边界的设置,通常设置到业务层,不要添加到Dao上
3、了解事务的几种传播特性
1. PROPAGATION_REQUIRED: 如果存在一个事务,则支持当前事务。如果没有事务则开启
2. PROPAGATION_SUPPORTS: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
3. PROPAGATION_MANDATORY: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
4. PROPAGATION_REQUIRES_NEW: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
5. PROPAGATION_NOT_SUPPORTED: 总是非事务地执行,并挂起任何存在的事务。
6. PROPAGATION_NEVER: 总是非事务地执行,如果存在一个活动事务,则抛出异常
7. PROPAGATION_NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务,
则按TransactionDefinition.PROPAGATION_REQUIRED 属性执行
4、Spring事务的隔离级别
1. ISOLATION_DEFAULT: 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
另外四个与JDBC的隔离级别相对应
2. ISOLATION_READ_UNCOMMITTED: 这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据。
这种隔离级别会产生脏读,不可重复读和幻像读。
3. ISOLATION_READ_COMMITTED: 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提
交的数据
4. ISOLATION_REPEATABLE_READ: 这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了避免下面的情况产生(不可重复读)。
5. ISOLATION_SERIALIZABLE 这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
除了防止脏读,不可重复读外,还避免了幻像读。
////////////////////////////////////////////////////////////////////////////////
spring+struts的集成(第一种集成方案)
原理:在Action中取得BeanFactory对象,然后通过BeanFactory获取业务逻辑对象
1、spring和struts依赖库配置
* 配置struts
--拷贝struts类库和jstl类库
--修改web.xml文件来配置ActionServlet
--提供struts-config.xml文件
--提供国际化资源文件
* 配置spring
--拷贝spring类库
--提供spring配置文件
2、在struts的Action中调用如下代码取得BeanFactory
BeanFactory factory = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession
().getServletContext());
为什么要这样写呢?
因为像factory的生成,如果每次执行以下action 都会实例化一次,BeanFactory factory = new ClassPathXmlApplicationContext
("applicationContext-beans.xml");
这样有必要吗?同时,会占用好多资源。
所以,我们会用到上述方法,在servlet初始化时,执行一次,以后就不用再实例化了。
但是我们必须在web.xml文件中配置一下信息。
//////////////////////////////////////// <context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext-*.xml,/WEB-INF/applicationContext-*.xml</param-value>
</context-param>
//////////////////////////////////////
/WEB-INF/applicationContext-*.xml指的是,具体的路径。而classpath*:applicationContext-*.xml指的是src根目录下的文件。
但是最终的<param-name>contextConfigLocation</param-name>中的值contextConfigLocation为唯一的。因为在类的方法属性中要一致。
////////////////////////////////////////
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
这是注册用的,就是是上述的配置有效。
////////////////////////////////////////
3、通过BeanFactory取得业务对象,调用业务逻辑方法
ApplicationContext pc = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession().getServletContext
());
UserManager userManager = (UserManager)pc.getBean("userManager");
为什么这样可以?因为ApplicationContext 继承了BeanFactory。其实都是一样的。就像ArrayList继承List一样的意思。
////////////////////////////////////////
////////////////////////////////////////
spring+struts的集成(第二种集成方案)
原理:将业务逻辑对象通过spring注入到Action中,从而避免了在Action类中的直接代码查询
1、spring和struts依赖库配置
* 配置struts
--拷贝struts类库和jstl类库
--修改web.xml文件来配置ActionServlet
--提供struts-config.xml文件
--提供国际化资源文件
* 配置spring
--拷贝spring类库
--提供spring配置文件
////////////////////////////////////////
2、因为Action需要调用业务逻辑方法,所以需要在Action中提供setter方法,让spring将业务逻辑对象注入过来
private UserManager userManager;
public void setUserManager(UserManager userManager) {
this.userManager = userManager;
}
////////////////////////////////////////
3、在struts-config.xml文件中配置Action
* <action>标签中的type属性需要修改为org.springframework.web.struts.DelegatingActionProxy
DelegatingActionProxy是一个Action,主要作用是取得BeanFactory,然后根据<action>中的path属性值
到IoC容器中取得本次请求对应的Action
///////////////////////////////////////////////////////////////////////////////////////////////////////////
<action path="/login"
type="org.springframework.web.struts.DelegatingActionProxy"
name="loginForm"
scope="request"
>
<forward name="success" path="/success.jsp"/>
</action>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
4、在spring配置文件中需要定义struts的Action,如:
//////////////////////////////////////////////////////////////////////////////////////////////////
<bean name="/login" class="com.bjsxt.usermgr.actions.LoginAction" scope="prototype">
<property name="userManager" ref="userManager"/>//因为在Action定义了private UserManager userManager;就是业务
//逻辑对象
</bean>
//////////////////////////////////////////////////////////////////////////////////////////////
* 必须使用name属性,name属性值必须和struts-config.xml文件中<action>标签的path属性值一致
* 必须注入业务逻辑对象
* 建议将scope设置为prototype,这样就避免了struts Action的线程安全问题,因为这样设置,每次调用返回不同的实例,
而将scope设置为singleton,每次调用只生成一个实例。
//////////////////////////////////////////////////////////////////////////////////////////////////
此时的一个感觉就是,要想把相应的类注入Ioc容器中的同时,将关联类的对象也注入,可以在该类的中定义像private
UserManager userManager;然后再设置set方法即可,一般注入用到的都是set方法吧。(此时的感觉认识。)
但是在Spring的配置文件中,还要定义相应的对象bean标签,然后包容的类中在引用id即可。
就是:
<bean id="userManager" class="com.bjsxt.usermgr.manager.UserManagerImpl"/>
<bean name="/login" class="com.bjsxt.usermgr.actions.LoginAction" scope="prototype">
<property name="userManager" ref="userManager"/>
</bean>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
在一些类中定义的方法是static类型的,那么像引用this.getHibernateTemplate()就会出错。因为this代表的是实例化。
示例:
下面:
private static SessionFactory sessionFactory;
public static List getItemCategoryList() {
List itemCategoryList = null;
try {
HibernateTemplate ht = new HibernateTemplate(sessionFactory);
return ht.find("from ItemCategory a order by a.id");
}catch(Exception e) {
//记录日志,log4j等......
e.printStackTrace();
}
return itemCategoryList;
}
public void setSessionFactory(SessionFactory sessionFactory) {
Functions.sessionFactory = sessionFactory;
}
说明:在方法getItemCategoryList中因为是static类型的,不能用this.getHibernateTemplate()获得HibernateTemplate 对象,又因为
HibernateTemplate 实例是通过sessionFactory获得的,所以只要在类中再定义即可,因为在static中引用,所以还要定义为static类型的,
同时要注入spring,还要定义set方法。
///////////////////////////////////////////
还有像Spring中对象的注入,如果设置的set方法是static那么也不会注入成功。在Spring配置文件中标签<listener></listener>的作用,就
是读取与spring的配置有关的文件的,像hinbernate.cfg.xml像struts-config.xml等等。
////////////////////////////////////////
- Spring初始了解笔记
- Hibernate初始了解笔记汇集
- 初始Spring
- spring 01 -spring初始
- javaee 框架的初始了解
- javaee 框架的初始了解
- spring-boot-笔记-2-thymeleaf初步了解
- 初始Spring Mvc
- Spring-Boot初始篇
- 初始spring(三)
- 初始spring(七)
- 初始spring(八)
- 初始Spring MVC
- spring 初始小例子
- Spring4-1 Spring初始
- 初始Spring(一)
- spring--总体初始
- QtGui学习笔记初始
- (转)UDP协议的两个主要方法sendto和recvfrom详解
- BREW的resource编辑器学习
- LTP测试流程及分析
- BREW的基本机制小结
- SqlCommand对象
- Spring初始了解笔记
- BREW开发俄罗斯方块(一)——设计
- sls ~简单的逻辑服务器
- SQL Server over和CTE的妙用(子记录根据外键递归找出父记录,并实现层级关系码)
- 将一个string日期(2010-02-01)的格式表示成01- Jan-2010
- 关于音响的MP3解码方案
- 说说大型高并发高负载网站的系统架构(from tianya)
- VIM开发C/C++插件cvim的安装及使用
- BREW开发俄罗斯方块(二)——点滴记录(更新中)