Spring AOP的实现原理

 

AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。

 

实现原理

jdk的动态代理和cglib

  有接口 没有接口
@EnableAspectJAutoProxy(proxyTargetClass = true)/
<aop:aspectj-autoproxy proxy-target-class="true"/>
cglib cglib
@EnableAspectJAutoProxy(proxyTargetClass = false)/
<aop:aspectj-autoproxy proxy-target-class="false"/>
jdk的动态代理 cglib

 

 

 

 

 

 

1.proxyTargetClass = true 有接口

 

2.proxyTargetClass = true 没有接口

 

3.proxyTargetClass =false 有接口

4.proxyTargetClass =false 没有接口

代码

//配置类
@Configuration @ComponentScan(
"com.jt.springAOP") @EnableAspectJAutoProxy(proxyTargetClass = false) public class Appconfig { }
//aop
@Component @Aspect
public class LubanAspect { @Pointcut("execution(* com.jt.springAOP.dao.*.*(..))") public void pointCut(){ } @Before("pointCut()") public void before(){ System.out.println("AOP-----pointCut"); } }

//接口
public interface IndexDao { void query(); }
//接口的实现类
@Component("dao")
public class IndexDaoImpl {
    public void query() {
        System.out.println("dao ---------------- query");
    }
}
//测试方法
public
class Test { public static void main(String[] args) { AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Appconfig.class); IndexDaoImpl bean = (IndexDaoImpl) annotationConfigApplicationContext.getBean("dao"); bean.query(); } }

 

动态代理模式实现

代理类

public class LoggingProxy {

    private Calculate calculate;

    LoggingProxy(Calculate calculate) {
        this.calculate = calculate;
    }

    public Calculate getCalculateLog() {
        Calculate calculateLog = null;

        //代理对象由哪一个类加载器负责加载
        ClassLoader loader = this.calculate.getClass().getClassLoader();
        //代理对象的类型,有哪些方法
        Class[] interfaces = new Class[]{Calculate.class};
        InvocationHandler h = new InvocationHandler() {
            /**
             * proxy: 代理对象。 一般不使用该对象
             * method: 正在被调用的方法
             * args: 调用方法传入的参数
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName = method.getName();
                //打印日志
                System.out.println("调用方法 " + methodName + " 参数 " + Arrays.asList(args));

                //调用目标方法
                Object result = null;

                try {
                    //前置通知

                    result = method.invoke(calculate, args);
                  
                    //返回通知, 可以访问到方法的返回值
                } catch (NullPointerException e) {
                    e.printStackTrace();
                    //异常通知, 可以访问到方法出现的异常
                }

                //后置通知. 因为方法可以能会出异常, 所以访问不到方法的返回值

                //打印日志
                System.out.println("结果: " + result);
                return result;
            }
        };

        calculateLog = (Calculate) Proxy.newProxyInstance(loader, interfaces, h);
        return calculateLog;
    }
}



定义的接口
public interface Calculate {
    int add(int i, int j);
    int sub(int i, int j);

    int mul(int i, int j);
    int div(int i, int j);
}

实现类
public class CalculateImpl implements Calculate {
    @Override
    public int add(int i, int j) {
        return i + j;
    }

    @Override
    public int sub(int i, int j) {
        return i - j;
    }

    @Override
    public int mul(int i, int j) {
        return i * j;
    }

    @Override
    public int div(int i, int j) {
        return i / j;
    }

public static void main(String[] args) {
    Calculate calculate = new CalculateImpl();
    Calculate  arit = new LoggingProxy(calculate).getCalculateLog();
arit.add(1,3);
arit.sub(4,3);
arit.mul(4,5);
arit.div(6,3);
arit.div(6,0);

}

  



运行结果:

AOP应用

/**
 * 可以使用 @Order 注解指定切面的优先级, 值越小优先级越高
 */
@Order(2)
@Aspect
@Component
public class LoggingAspect {

   /**
    * 定义一个方法, 用于声明切入点表达式. 一般地, 该方法中再不需要添入其他的代码.
    * 使用 @Pointcut 来声明切入点表达式.
    * 后面的其他通知直接使用方法名来引用当前的切入点表达式.
    */
   @Pointcut("execution(public int *.*(..))")
   public void declareJointPointExpression(){}

   /**
    * 在 接口的每一个实现类的每一个方法开始之前执行一段代码
    */
   @Before("declareJointPointExpression()")
   public void beforeMethod(JoinPoint joinPoint){
      String methodName = joinPoint.getSignature().getName();
      Object [] args = joinPoint.getArgs();

      System.out.println("方法名 " + methodName + " 参数 " + Arrays.asList(args));
   }

   /**
    * 在方法执行之后执行的代码. 无论该方法是否出现异常
    */
   @After("declareJointPointExpression()")
   public void afterMethod(JoinPoint joinPoint){
      String methodName = joinPoint.getSignature().getName();
      System.out.println("方法名 " + methodName + " 结束");
   }

   /**
    * 在方法法正常结束受执行的代码
    * 返回通知是可以访问到方法的返回值的!
    */
   @AfterReturning(value="declareJointPointExpression()",
         returning="result")
   public void afterReturning(JoinPoint joinPoint, Object result){
      String methodName = joinPoint.getSignature().getName();
      System.out.println("方法名 " + methodName + " 返回结果 " + result);
   }

   /**
    * 在目标方法出现异常时会执行的代码.
    * 可以访问到异常对象; 且可以指定在出现特定异常时在执行通知代码
    */
   @AfterThrowing(value="declareJointPointExpression()",
         throwing="e")
   public void afterThrowing(JoinPoint joinPoint, Exception e){
      String methodName = joinPoint.getSignature().getName();
      System.out.println("方法名 " + methodName + " 异常:" + e);
   }

   /**
    * 环绕通知需要携带 ProceedingJoinPoint 类型的参数.
    * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint 类型的参数可以决定是否执行目标方法.
    * 且环绕通知必须有返回值, 返回值即为目标方法的返回值
    */

   @Around("declareJointPointExpression()")
   public Object aroundMethod(ProceedingJoinPoint pjd){

      Object result = null;
      String methodName = pjd.getSignature().getName();

      try {
         //前置通知
         System.out.println("方法名 " + methodName + " 参数 " + Arrays.asList(pjd.getArgs()));
         //执行目标方法
         result = pjd.proceed();
         //返回通知
         System.out.println("方法名 " + methodName + " 返回值 " + result);
      } catch (Throwable e) {
         //异常通知
         System.out.println("方法名 " + methodName + " 异常:" + e);
         throw new RuntimeException(e);
      }
      //后置通知
      System.out.println("方法名 " + methodName + " 结束");
      
      return result;
   }
}

  


xml配置
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
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.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

<!-- 配置自动扫描的包 -->
<context:component-scan base-package="com.atguigu.spring.aop"></context:component-scan>

<!-- 配置自动为匹配 aspectJ 注解的 Java 类生成代理对象 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

  


posted @ 2018-09-17 16:20  ●ら任┊逍遥  阅读(219)  评论(0编辑  收藏  举报