Spring1.x 2.x 3.x AOP的区别

Spring1.x, 2.x, 3.x 对于AOP的实现方式不一样。

Spring AOP是通过动态代理模式实现的,利用了java的反射机制。
在了解动态代理之前,先要知道什么是静态代理。
代理模式,就是在客户类和目标类之间增加了一个代理类,这个代理类和目标类实现了同样的借口。这样,客户类通过调用代理类来间接的访问目标类。在代理类中调用目标类同样接口的方法。这样在代理类中就可以在调用目标类的方法之前和之后做一些操作。
静态代理,是指在代理类的构造函数中静态地制定了目标类。所谓静态,就是指在编写代码的时候制定,这样编译之后就不能改了。
动态代理,是利用了java的反射机制,在运行时动态地制定目标类。具体实现方式是,代理类实现 java.lang.reflect.InvocationHandler接口,实现接口中的invoke()方法,在Method.invoke(targetObject, args);调用之前和之后可以做一些操作。在代理类中自定义一个set方法,或者叫createProxy(Object targetObject),方法签名中有一个参数,是目标类。注意,这里目标类的类型是Object。所以,可以在运行时指定任何需要的目标类(目标类必须实现一个接口)。在这个方法中调用Proxy.newProxyInstance(ClassLoader loader,  Class<?>[] interfaces,  InvocationHandler h)来生成实现同一接口(目标类实现的接口)的代理类。Proxy.newProxyInstance()方法返回的是一个Object类型对象,在客户类中可以通过强制类型转换,把该对象转换成接口。然后调用该接口的业务方法,就会触发InvocationHandler接口实现类中的invoke()方法,从而达到代理的目的。
 
Spring1.x中的AOP是侵入式的,advice需要实现spring的接口MethodBeforeAdvice和AfterReturningAdvice,在applicationContext.xml中配置org.springframework.aop.framework.ProxyFactoryBean类作为代理类。例如
<bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
在其中指定接口列表和拦截器列表(也就是advice列表),同时指定目标类。例如:
-----------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    " http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!-- spring1.x -->
<!-- 定义目标类 -->
<bean id="userTarget" class="com.freesky.proxy.UserTargetImpl" />
<!-- 定义通知 -->
<!-- 前置通知 -->
<bean id="beforeLogAdvice" class="com.freesky.aop.BeforeLogAdvice" />
<!-- 后置通知 -->
<bean id="afterLogAdvice" class="com.freesky.aop.AfterLogAdvice" />

<!-- 代理类作用: 生成代理类,织入通知 -->
<bean id="userProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces">
<!-- 可以添加多个接口 -->
<list>
<value>com.freesky.proxy.IUser</value>
</list>
</property>
<!-- 引入通知 -->
<property name="interceptorNames">
<list>
<value>beforeLogAdvice</value>
<value>afterLogAdvice</value>
</list>
</property>
<!-- 目标对象 -->
<property name="target" ref="userTarget" />
</bean>
</beans>
------------------------------------------------------------------------------------------
 
Spring2.x就不需要代码实现spring的接口,advice类就是一个pojo。在applicationContext.xml中通过<aop:config>来配置。其中引入了<aop:pointcut>。配置文件略显繁琐。完整的配置如下:
--------------------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=" http://www.springframework.org/schema/beans"
xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" xmlns:p=" http://www.springframework.org/schema/p"
xmlns:aop=" http://www.springframework.org/schema/aop" xmlns:context=" http://www.springframework.org/schema/context"
xmlns:jee=" http://www.springframework.org/schema/jee" xmlns:tx=" http://www.springframework.org/schema/tx"
xsi:schemaLocation="  
         http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jee  http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

<!-- spring2.x后 -->
<!-- 目标对象 -->
<bean id="userImpl" class="com.freesky.proxy.impl.UserTargetImpl" />
<!-- 通知 -->
<bean id="logAdvice" class="com.freesky.advice.LogAdvice" />

<aop:config>
<aop:aspect id="logAspect" ref="logAdvice">
<!-- 切入点 -->
<!--  
<aop:pointcut id="beforePointCut" expression="execution(* sayHello*(..))" />
<aop:pointcut id="afterPointCut" expression="execution(* sayHello*(..))" />
-->
<aop:pointcut id="beforePointCut" expression="execution(* com.freesky.proxy.impl..*.*(..))" />
<aop:pointcut id="afterPointCut" expression="execution(* sayHello*(..))" />

<!-- 织入(通知作用于切入点) -->
<aop:before method="beforeLog" pointcut-ref="beforePointCut" />
<aop:after method="afterLog" pointcut-ref="afterPointCut" />
</aop:aspect>
</aop:config>
</beans>
-----------------------------------------------------------------------------------------------------
 
Spring3.x在AOP方面大大简化了开发工作量,通过annotation注解的方式在java代码中配置,而applicationContex.xml中只要一个配置<aop:aspectj-autoproxy />就可以自动实现AOP了。当然这个配置要和另外两个配置以前使用。
   <context:annotation-config />
    <context:component-scan base-package="com.freesky"/>
完整的配置如下:
------------------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=" http://www.springframework.org/schema/beans"
      xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance"
      xmlns:aop=" http://www.springframework.org/schema/aop"
      xmlns:context=" http://www.springframework.org/schema/context"
      xsi:schemaLocation="
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
       
    <context:annotation-config />
    <context:component-scan base-package="com.itsoft"/>
    <aop:aspectj-autoproxy />
</beans>
------------------------------------------------------------------
 
参考文献:
Spring1.x 2.x 动态代理
    Spring AOP动态代理原理与实现方式
Spring3.x
   spring AOP @Around @Before @After 区别

猜你喜欢

转载自freesky-zh.iteye.com/blog/2187608