spring IOC容器就是普通的JavaBean,只是它提供了一些特殊功能,它可以存放其他的对象,而且提供了访问路径。我们可以将IOC容器理解为BeanFactory或者ApplicationContext。BeanFactory是IOC容器的底层实现,ApplicationContext是建立在BeanFactory之上的。BeanFactory需要一个Resource来加载配置文件,其中Resource有两种实现方式:ClassPathResource从类路径加载资源,FileSystemResource从文件系统加载资源。ApplicationContext加载配置文件的方式有两种:ClassPathXmlApplicationContext、FileSystemXmlApplicationContext。
spring使用配置文件来描述bean与bean之间的关系,并且由IOC容器来实例化这些bean。IOC容器在装配bean的时候,先调用构造函数创建一个对象,然后通过反射调用对象的各个set方法为对象的属性赋值,最后这个bean会被缓存起来等待被使用。
bean的配置:
(1)属性注入。
<bean id="myBook" class="model.Book">
<property name="id" value="000001"/>
</bean>
需要注入的属性在类中必须有set方法,必须有默认的构造函数,尤其当类中有一个显性的非默认构造函数,这时,必须再重新添加一个默认构造函数。
(2)bean的依赖关系。
<bean id="dt" class="java.util.Date"></bean>
<bean id="person" class="model.Person">
<property name="name" value="zhao">
<property name="birthday" ref="dt"/>
</bean>
(3)集合的注入。
有一个类JavaBookStore:
package model;
import java.util.*;
public class JavaBookStore{
private List commonBooks;
private Set favorites;
private Map publisherMappings;
private HashMap<String,String> gysInfor;
public List getCommonBooks(){
return commonsBooks;
}
public void setCommonBooks(List commonBooks){
this.commonBooks = commonBooks;
}
public Set getFavorites(){
return favorites;
}
public void setFavorites(Set favorites){
this.favorites = favorites;
}
public Map getPublisherMappings(){
return publisherMappings;
}
public void setPublisherMappings(Map publisherMappings){
this.publisherMappings = publisherMappings;
}
public HashMap<String,String> getGysInfor(){
return gysInfor;
}
public void setGysInfor(HashMap<String,String>gysInfor){
this.gysInfor= gysInfor;
}
则配置如下:
<bean id="javaBookStore" class="model.JavaBookStore">
<property name="commonBooks">
<list>
<ref bean="myBook1"/>
<ref bean="myBook2"/>
<ref bean="myBook3"/>
</list>
</property>
<property name="favorites">
<set>
<ref bean="myBook1"/>
<ref bean="myBook2"/>
<ref bean="myBook3"/>
</set>
</property>
<property name="publisherMappings">
<map>
<entry key="phei" value="Publishing House of Electronics Industry"/>
<entry key="cmp" value="China machine Press"/>
<entry key="ptp" value="Post and TeleCOM Press"/>
<entry key-ref="myBook1" value-ref="myBook1"/>
<entry key="rmrb">
<ref bean="myBook2">
</entry>
</map>
</property>
<property name="gysinfor">
<props>
<prop key="name">wangli</prop>
</props>
</property>
</bean>
(4)bean的作用域。
bean有五种作用域:singleton,prototype,request,session,globalSession,其中后面三种在WebApplicationContext中才有效,默认的作用域为singleton。singleton只会实例化一次,singleton的bean还可以指定lazy-init属性,<bean id="dt" class="java.util.Date" lazy-init="true"></bean>表示只有用到bean的时候才实例化。
IOC容器的高级特性涉及到属性编辑器,使用外部属性文件,国际化,容器事件等。
(1)属性编辑器的作用就是将配置文件中字面量转换为bean的属性对应的类型,spring为基本的数据类型包括包装类型、集合类型(List,Set,Map,Collection)、资源类型(File,Class,Local,Resource,InoutStream,URL)提供了默认的属性编辑器。
(2)我们经常把数据库连接用的用户名、密码单独放在一个properties文件中,但是我们希望在bean的配置文件中使用它,例如db.properties文件如下:
jdbc.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc.url=jdbc:microsoft:sqlserver://localhost:2431
jdbc:username=sa
jdbc.password=123456
该文件放在classpath下面根目录下,我们需要把这个属性文件也注册到IOC容器:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:db.properties</value>
</list>
</property>
</bean>
配置一个DataSource并且使用这个属性文件:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
Sping AOP的目的就是要把和核心逻辑无关的却又无法消除的代码(比如事物控制代码)从核心代码中剥离出来,使业务逻辑类专注于业务逻辑,并且在适当的时候(比如运行时)再把他们植入到核心业务代码中。
(1)增强(Advice)
把性能监测和事物控制的逻辑除掉之后,如果想继续使用性能监测和事物控制,则要做两件事情:
一是创建增强Advice,把性能监测和事物控制的代码放到增强里面;二是用一种灵活的方式把增强植入到干净的业务实现类中。Spring提供了前置增强MethodBeforeAdvice、后置增强AfterReturningAdvice、环绕增强MethodInterceptor、异常抛出增强ThrowsAdvice等。一个前置增强的例子:
package aop;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class BookServiceBeforeAdvice implements MethodBeforeAdvice{
public void before(Method method,Object[] args,Object obj) throws Throwable{
System.out.println("advice before method" +obj.getClass().getName() + "." + method.getName() + "().");
}
}
通过代理工厂ProxyFactory把Advice植入到目标对象BookService并且产生代理对象。
package aop;
import model.Book;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
public class TestAdvice{
public static void main(String[] args){
BookService target = new BookServiceImpl();
BeforeAdvice advice = new BookServiceBeforeAdvice();
ProxyFactory pf = new ProxyFactory();
pf.setTarget(target);
pf.addAdvice(advice);
BookService service = (BookService)pf.getProxy();
service.insertBook(new Book());
service.removeBook(new Book());
}
}
一个后置增强的例子:
package aop;
impport java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class BookServiceAfterReturningAdvice implements AfterReturningAdvice{
public void afterReturning(Object returnObj,Method method,Object[] args,Object target) throws Throwable{
System.our.println("method " + target.getClass().getName() + "." + method.getName() + "() has beean executed.");
}
}
一个环绕增强的例子:
package aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class BookServcieInterceptor implements MethodInterceptor{
public Object invoke(MethodInvocation invocation) throws Throwable{
Object[] args = invocation.getArguments();//获取目标方法参数
System.out.println("the method " + invocation.getThis().getClass().getName() + "." + invocation.getMethod().getName() + "() will be
executed.");
Object obj = invocation.proceed();//执行目标方法
Ssystem.out.println("the method " + invocation.getThis().getClass().getName() + "." + invocation.getMethod().getName() + "() has been
executed.");
return obj;
}
}
上面的各种增强可以通过配置文件来实现:
<bean id="beforeAdvice" class="aop.BookServiceBeforeAdvice"/>
<bean id="afterAdvice" class="aop.BookServiceAfterReturningAdvice"/>
<bean id="interceptor" class="aop.BookServiceInterceptor"/>
<bean id="targetService" class="aop.BookServiceImpl"/>
<bean id="bookService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<values>aop.BookServcie</value>
</property>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
<value>afterAdvice</value>
<value>interceptor</value>
</list>
</property>
<property name="targetName">
<value>targetService</value>
</property>
</bean>
(2)切面
增强作用于一个类的所有方法,也就是说增强不能定位到具体的方法,但有的时候我们只希望某些方法得到增强,比如有一个BookService,它有
insertBook,updateBook,deleteBook,getAll,findById等方法,但是只需要对insert,update,delete开头的方法开启事物,那就需要用到切面。切面包含增
强,同时还包括一个方法匹配器。切面有动态切面和静态切面,下面是一个静态正则表达式方法匹配切面的用法:
<bean id="regexpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="patterns">
<list>
<value>insert*</value>
<value>remove*</value>
</list>
</property>
<property name="advice" ref="beforeAdvice"/>
</bean>
<bean id="bookService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<values>aop.BookServcie</value>
</property>
<property name="interceptorNames">
<list>
<value>beforeAdvice</value>
<value>afterAdvice</value>
<value>interceptor</value>
<value>regexpAdvisor</value>
</list>
</property>
<property name="targetName">
<value>targetService</value>
</property>
</bean>
spring事物管理
(1)spring事物管理的第一种配置方式:为每一个目标bean配置一个代理
<bean id="companyDao" class="dao.hibernate.CompanyDaoImpl">
<property name="hibernateTemplate" ref="hibernateTemplate"/>
</bean>
<bean id="companyServiceTarget" class="services.CompanyServcie">
<property name="companyDao" ref="companyDao"/>
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="companyService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager"/>
<property name="target" ref="companyServiceTarget"/>
<property name="optimize" value="true"/><!-- optimize可选,true代表使用CGLib,false代表使用jdk proxy -->
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="list">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
(2)spring事物管理的第二种配置方式:目标bean共享代理基类
<bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager" ref="txManager"/>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="list">PROPAGATION_REQUIRED,readOnly</prop>
</props>
</property>
</bean>
<bean id="companyService" parent="baseTransactionProxy">
<property name="target" ref="companyServiceTarget"/>
</bean>
<bean id="otherService" parent="baseTransactionProxy">
<property name="target" ref="otherServiceTarget"/>
</bean>
(3)spring事物管理第三种配置方式:使用拦截器
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="txManager"/>
<property name="transactionAttributes">
<props>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames">
<list>
<value>companyServiceTarget</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>transactionInterceptor</value>
</list>
</proerty>
</bean>
这时可以直接使用companyServiceTarget。
(4)spring事物管理的第四种配置方式:使用tx命名空间
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="list" propagation="REQUIRED" read-only="true"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="interceptorPointCuts" expression="execution(* services.*Service(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts"/>
</aop:config>
使用这种配置就需要把tx,aop的命名空间加入xml配置文件的开始。
<beans xmlns
xmlns:xsi
xmlns:p
xmlns:context
xmlns:aop
xmlns:tx
xsi:schemaLocation