JavaSpringAOPAspectJ

区别

AspectJ

AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

Spring aop

Spring提供了四种类型的Aop支持

  • 基于经典的SpringAOP
  • 纯POJO切面
  • @ASpectJ注解驱动的切面
  • 注入式AspectJ切面(其实与Spring并无多大的关系,这个就是使用AspectJ这个框架实现Aop编程)

    基于经典的SpringAop

    其使用ProxyFactoryBean创建。
    增强(通知)的类型有:

  • 前置通知:org.springframework.aop.MethodBeforeAdvice

  • 后置通知:org.springframework.aop.AfterReturningAdvice
  • 环绕通知:org.aopalliance.intercept.MethodInterceptor
  • 异常通知:org.springframework.aop.ThrowsAdvice ```java public interface IBookDao { public int add() public int delete(); }

public class BookDaoImpl implements IBookDao{ public int add() { System.out.println(“正在添加图书…”); return 0; } public int delete() { System.out.println(“正在删除图书…”); return 0; } }

//实现了MethodInterceptor的环绕增强类 public class MyAdvice implements MethodInterceptor{

  1. public Object invoke(MethodInvocation invocation) throws Throwable {
  2. System.out.println("Around Advice before method invocation");
  3. Object o = invocation.proceed();
  4. System.out.println("Around Advice after method invocation");
  5. return o;
  6. }

}

  1. 将每一个连接点都当做切点(拦截每一个方法)
  2. ```xml
  3. <bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean>
  4. <bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean>
  5. <bean id="bookDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
  6. <property name="target" ref="bookDao"/>
  7. <property name="proxyInterfaces" value="com.njust.learning.spring.service.IBookDao"/>
  8. <property name="interceptorNames" value="myadvice"/>
  9. </bean>

使用RegexMethodPointcutAdvisor针对某些特定的方法进行拦截增强

  1. <bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean>
  2. <bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean>
  3. <bean id="rmpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  4. <!--patterns,如果有多个指定的值的话,可以使用,隔开,例如value=".*add,.*delete"-->
  5. <property name="patterns" value=".*add"/>
  6. <property name="advice" ref="myadvice"/>
  7. </bean>
  8. <!--使用的时候使用这个id,而不是原始的那个id-->
  9. <bean id="bookDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
  10. <property name="target" ref="bookDao"/>
  11. <property name="proxyInterfaces" value="com.njust.learning.spring.service.IBookDao"/>
  12. <property name="interceptorNames" value="rmpAdvisor"/>
  13. </bean>

注意:像上面这样,每定义一个dao都需要定义一个ProxyFactoryBean,显得很麻烦,所以引入自动代理,也就是自动创建代理对象。

BeanNameAutoProxyCreator

  1. <bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean>
  2. <bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean>
  3. <bean id="rmpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  4. <!--patterns,如果有多个指定的值的话,可以使用,隔开,例如value=".*add,.*delete"-->
  5. <property name="patterns" value=".*add"/>
  6. <property name="advice" ref="myadvice"/>
  7. </bean>
  8. <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
  9. <property name="beanNames" value="*Dao"></property>
  10. <property name="interceptorNames" value="rmpAdvisor"></property>
  11. </bean>

DefaultAdvisorAutoProxyCreator

  1. <bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean>
  2. <bean id="myadvice" class="com.njust.learning.spring.aop.MyAdvice"></bean>
  3. <bean id="rmpAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  4. <!--patterns,如果有多个指定的值的话,可以使用,隔开,例如value=".*add,.*delete"-->
  5. <property name="patterns" value=".*add"/>
  6. <property name="advice" ref="myadvice"/>
  7. </bean>
  8. <!--根据切面中生成信息生成代理-->
  9. <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

纯POJO切面,需要使用XML进行配置

  1. public interface IBookDao {
  2. public int add();
  3. public int delete();
  4. }
  5. public class BookDaoImpl implements IBookDao{
  6. public int add() {
  7. int a = 1/0;
  8. System.out.println("正在添加图书...");
  9. return 0;
  10. }
  11. public int delete() {
  12. System.out.println("正在删除图书...");
  13. return 0;
  14. }
  15. }
  1. public class PojoAdvice {
  2. public void before(){
  3. System.out.println("前置通知");
  4. }
  5. public void after(Object returnval){
  6. System.out.println("后置通知"+",处理后的结果为:"+returnval);
  7. }
  8. public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
  9. System.out.println("环绕前置增强...");
  10. Object o = proceedingJoinPoint.proceed();
  11. System.out.println("环绕后置增强...");
  12. return o;
  13. }
  14. public void afterThrowing(Throwable e){
  15. System.out.println("异常通知:"+e.getMessage());
  16. }
  17. }
  1. <bean id="bookDao" class="com.njust.learning.spring.service.BookDaoImpl"></bean>
  2. <bean id="pojoAdvice" class="com.njust.learning.spring.pojoaop.PojoAdvice"></bean>
  3. <aop:config>
  4. <aop:pointcut id="p" expression="execution (* *.add(..))"/>
  5. <aop:aspect ref="pojoAdvice">
  6. <aop:before method="before" pointcut-ref="p"></aop:before>
  7. <!--通过设置returning来将返回值传递给通知-->
  8. <aop:after-returning method="after" pointcut-ref="p" returning="returnval"/>
  9. <aop:around method="around" pointcut-ref="p"/>
  10. <!--通过设置returning来将异常对象传递给通知-->
  11. <aop:after-throwing method="afterThrowing" pointcut-ref="p" throwing="e"/>
  12. </aop:aspect>
  13. </aop:config>

联系

借助于Spring Aop的命名空间可以将纯POJO转换为切面,实际上这些POJO只是提供了满足切点的条件时所需要调用的方法,但是,这种技术需要XML进行配置,不能支持注解。
所以Spring借鉴了AspectJ的切面,以提供注解驱动的AOP,本质上它依然是Spring基于代理的AOP,只是编程模型与AspectJ完全一致,这种风格的好处就是不需要使用XML进行配置。
使用@Aspect方式,就可以在类上直接一个@Aspect就搞定,不用费事在xml里配了。但是这需要额外的jar包(aspectjweaver.jar)。因为Spring直接使用AspectJ的注解功能,注意只是使用了它 的注解功能而已,并不是核心功能 。
SpringAop的底层技术依然是Jdk动态代理和Cglib。