SpringAOP提供的优势
1、允许开发者声明企业级服务,比如:事务服务、安全性服务。EJB组件能够使用J2EE容器提供声明式服务。但是需要借助于EJB组件,而SpringAOP却不需要EJB容器,即借助于Spring的事务抽象框架能够在EJB容器外部使用企业级、声明式服务。
2、开发者可以开发满足业务需求的自定义方面。类似于JBOSS服务器中拦截器开发一样,如果标准的J2EE安全性不能满足业务需求,则必须开发拦截器。
3、开发SpringAOP advice很方便,这些AOP Advice不仅仅POJO类,借助于Spring提供的ProxyFactoryBean,能够迅速的搭建Spring AOP Advice
Spring AOP的装备
1、before装备:在执行目标之前执行的装备
使用接口org.springframework.aop.MethodBeforeAdvice
源码如下:
public class LoggingBeforeAdvice implements MethodBeforeAdvice{
protected static final Log log = LogFactory.getLog(LoggingBeforeAdvice.class);
public void before(Method arg0,Object[] arg1,Object arg2){
// before do something
}
}
该方法在
调用目标操作之前调用,这很适用于那些有安全性要求的方法,即在调用目标操作之前检查客户身份。开发者还需要提供application.xml文件。
<beans>
<bean id="helloworldbean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.openv.spring.IHelloWorld</value>
</property>
<property name="target">
<ref local="helloworldbeanTarget"/>
</property>
<property name="interceptorNames">
<list>
<value>loggingBeforeAdvisor</value>
</list>
</property>
</bean>
<bean id="helloworldbeanTarget" class="com.openv.spring.HelloWorld" />
<bean id="loggingBeforeAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="loggingBeforeAdvice" />
</property>
<property name="pattern">
<value>.*</value>
</property>
</bean>
<bean id="loggingBeforeAdvice" class="com.openv.spring.LoggingBeforeAdvice" />
</beans>
其中借助了RegexpMethodPointcutAdvisor类实现了对LoggingBeforeAdvice装备的集成,以完成pointcut和拦截器的定义。
2、Throws装备:如果目标操作在执行过程中抛出了异常,该装备会执行,可以采用Java捕捉异常而不用对异常信息或throwable进行造型
使用接口org.springframework.aop.ThrowsAdvice
对于处理事务或者特定业务需求很有帮助,源码如下:
public interface IHelloWorld{
public String getContext(String helloworld) throws Exception;
}
public class HelloWorld implements IHelloWorld{
protected static final Log log = LogFactory.getLog(HelloWorld.class);
public String getContext(String helloworld) throws Exception{
// do something
throw new Exception();
}
}
LoggingThrowsAdvice的装备代码如下:
public class LoggingThrowsAdvice implements ThrowsAdvice{
protected Log log = LogFactory.getLog(LoggingThrowsAdvice.class);
public void afterThrowing(Method method,Object[] args,Object target,Throwable subclass){
// throw some Exception
}
}
其实现了afterThrowing方法,当异常抛出时,该装备即被激活,具体的Spring配置文件如下:
<bean id="helloworldbean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.openv.spring.IHelloWorld</value>
</property>
<property name="target">
<ref local="helloworldbeanTarget" />
</property>
<property name="interceptorNames">
<list>
<value>loggingThrowsAdvisor</value>
</list>
</property>
</bean>
<bean id="helloworldbeanTarget" class="com.openv.spring.HelloWorld" />
<bean id="loggingThrowsAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="loggingThrowsAdvice">
</property>
<property name="pattern">
<value>.*</value>
</property>
</bean>
<bean id="loggingThrowsAdvice" class="com.openv.spring.LoggingThrowsAdvice" />
应用抛出Exception后,LoggingThrowsAdvice的AfterThrowing即被激活
3、After装备:在执行目标之后执行的装备
After状态在执行密保操作之后执行装备中的afterReturnning方法。具体的LoggingAfterAdvice实现如下:
public class LoggingAfterAdvice implements AfterRuturningAdvice{
protected static final Log log = LogFactory.getLog(LoggingAfterReturnningAdvice.class);
public void afterReturnning(Object object,Method m,Object[] args,Object target) throws Throwable(
// after do something
)
}
配置文件:
<bean id="helloworldbean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>com.openv.spring.IHelloWorld</value>
</property>
<property name="target">
<ref local="helloworldbeanTarget" />
</property>
<property name="interceptorNames">
<list>
<value>loggingAfterAdvisor</value>
</list>
</property>
</bean>
<bean id="helloworldbeanTarget" class="com.openv.spring.HelloWorld"/>
<bean id="loggingAfterAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advisor">
<ref local="loggingAfterAdvice" />
</property>
<property name="pattern">
<value>.*</value>
</property>
</bean>
<bean id="loggingAfterAdvice" class="com.openv.spring.LoggingAfterAdvice" />
使用接口org.springframework.aop.AfterReturningAdvice
对于代理Java接口的场景,Spring默认时是采用动态代理实现的,对于代理Java类的场景Spring采用动态字节码(byte-code)生成技术,比如使用了CGLIB库。
4、Around装备:在调用方法前后执行的装备。功能最强大,能够在目标操作执行前后实现特定的行为,使用灵活。
使用接口org.springframework.aop.MethodInterceptor
功能最强大,灵活性最好,能够在执行目标前后执行,这对一些需要做资源初始化和释放操作的应用特别有用,具体代码分析如下:
public class LoggingAroundAdvice implements MethodInterceptor{
protected static final Log log = LogFactory.getLog(LoggingAroundAdvice.class);
public Object invoke(MethodInvocation invocation) throws Throwable{
log.info("before:The Invocation of getContent()");
invocation.getArguments()[0] = "jader";
invocation.proceed();
log.info("after:The Inovation of getContent()");
return null;
}
}
配置文件如下:
<bean id="helloworldbean" class="org.springframework.aop.framework.ProxyFactoryBean" >
<property name="proxyInterfaces">
<value>com.openv.spring.IHelloWorld</value>
</property>
<property name="target">
<ref local="helloworldbeanTarget" />
</property>
<property name="interceptorNames">
<list>
<value>loggingAroundAdvisor</value>
</list>
</property>
</bean>
<bean id="loggingAroundAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="loggingAroundAdvice">
</property>
<property name="pattern">
<value>.*</value>
</property>
</bean>
<bean id="loggingAroundAdvice" class="com.openv.spring.LoggingAroundAdvice" />
5、Introduction装备:能够为类新增方法,最复杂
这几种接口之间的关系:
ProxyFactoryBean
ProxyFactoryBean引入了间接层。通过名字或者id(helloworldbean)获得的引用对象并不是ProxyFactoryBean实例本身,而是ProxyFactoryBean中getObject方法实现返回的对象。其中getObject方法将创建AOP代理,并将目标对象包裹(wrapper)在其中。那么ProxyFactoryBean到底是什么?
ProxyFactoryBean实现了org.springframework.beans.factory.FactoryBean接口,本身也是JavaBean,下面是其类图:
主要有以下几个属性:
proxyInterfaces:接口构成字符串列表,即接口集合
proxyTargetClass:是否使用CGLIB代理目标类的标志位动态代理能够对接口指定,如果目标是类则无能无力,因此需要借助于CGLIB库,实现类的子类,从而起到代理类的作用。
interceptorNames:拦截器名构成的字符串列表,拦截器集合
target:执行目标类
SingleTon:单实例的标志位,每次调用ProxyFactoryBean的getObject方法时是返回同一个对象还是返回不同的对象。
下面看下具体的代码:
public class HelloClient{
protected static final Log log = LogFactory.getLog(HelloClient.class);
public static void main(String[] args){
// 创建LoggingAroundAdvice装备
Advice advice = new LoggingAroundAdvice();
// 创建ProxyFactory,从而不需要借助Spring IOC容器提供反转功能
ProxyFactory factory = new ProxyFactory(new HelloWorld());
factory.addAdviced(advice);
IHelloWorld hw = (IHelloWorld)factory.getProxy();
log.info(hw.getContext("jader"));
}
}
通过手工创建AOP代理能够摆脱Spring IOC容器的依赖。
Spring框架开发team推荐:借助于Spring IOC框架自动创建AOP代理,并将有关AOP代理的Java代理通过Spring配置文件配置。
FactoryBean在Spring框架起了很重要的作用,ProxyFactoryBean实现了FactoryBean接口,借助于ProxyFactoryBean能够实现各种业务需求,但要求去额外开发很多辅助业务操作,比如事务、数据库连接。
对象池
先研究下application.xml
// 借助于spring框架对commons pool的有效支持,能够实现对helloworldbeanTarget的有效池化
// 同时还能设置对象池的最大数量
<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
<property name="targetBeanName">
<value>helloworldbeanTarget</value>
</property>
<property name="maxSize">
<value>25</value>
</property>
</bean>
// 通过ProxyFactoryBean中指定targetSource属性,便能够使用到poolTargetSource提供的强大功能
<bean id="helloworldbean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="targetSource">
<ref local="poolTargetSource" />
</property>
<property name="interceptorNames">
<list>
<value>loggingAroundAdvisor</value>
</list>
</property>
</bean>