spring aop工作原理
创始人
2024-11-18 00:20:55
0次

spring aop原理:1、AOP 面向切面,是一种编程范式,提供从另一个角度来考虑程序结构以完善面向对象编程OOP;2、AOP为开发者提供了一种描述横切关注点的机制,并能够自动将横切关注点织入到面向对象的软件系统中。

spring aop原理:

AOP(面向切面)是一种编程范式,提供从另一个角度来考虑程序结构以完善面向对象编程(OOP)。

AOP为开发者提供了一种描述横切关注点的机制,并能够自动将横切关注点织入到面向对象的软件系统中,从而实现了横切关注点的模块化。

AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任,例如事务处理、日志管理、权限控制等,封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。

使用AOP的好处

  • 降低模块的耦合度

  • 使系统容易扩展

  • 提高代码复用性

AOP的基本概念

  • 连接点(JoinPoint):需要在程序中插入横切关注点的点,连接点可能是在类初始化、方法调用、字段调用或处理异常等等。Spring中只支持方法执行连接点。

  • 切入点(Pointcut):一组相关连接点的集合。

  • 通知(Advice):在连接点上执行的行为,增强提供了在AOP中需要在切入点所选择的连接点处进行扩展现有行为的手段。包括前置增强(before advice)、后置增强 (after advice)、环绕增强 (around advice)。

  • 切面(Aspect):通知和切入点的结合。

  • 织入(Weaving):织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程。

  • 代理(Proxy):通过代理方式来对目标对象应用切面。AOP代理可以用JDK动态代理或CGLIB代理实现。

  • 目标对象(Target):需要被织入关注点的对象。即被代理的对象。

spring aop工作原理

实现AOP的主要设计模式就是动态代理。

Spring的动态代理有两种:一是JDK的动态代理;另一个是cglib动态代理。

JDK动态代理模拟

JDK动态代理的两个核心接口(类)分别是InvocationHandler和Proxy。注意:只能代理接口。

public class TimeHandler implements InvocationHandler {  
      
    // 目标对象  
    private Object targetObject;  
    
    public TimeHandler(Object targetObject){
          this.targetObject = targetObject;
    }
    @Override  
    //关联的这个实现类的方法被调用时将被执行  
    /*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,      
        args表示方法的参数*/  
    public Object invoke(Object proxy, Method method, Object[] args)  
            throws Throwable {  
        Object ret=null;  
        try{  
            System.out.println("方法之前:"+System.currentTimeMillis());    
            //调用目标方法  
            ret=method.invoke(targetObject, args);  
            System.out.println("方法之后:"+System.currentTimeMillis());  
        }catch(Exception e){  
            e.printStackTrace();  
            System.out.println("error");  
            throw e;  
        }  
        return ret;  
    }  
  
}

TimeHandler 类实现了InvocationHandler接口。实现核心方法invoke,共有3个参数。第一个参数 生成的代理类实例,第二个参数 目标对象的方法,第三个参数 方法的参数值数组。

public class ProxyUtil {
    
    @SuppressWarnings("unchecked")
    public static  T proxyOne(ClassLoader loader,Class[] clz,InvocationHandler handler){
        return (T)Proxy.newProxyInstance(loader, clz, handler);
    }
}

ProxyUtil 类简单封装了一下Proxy.newProxyInstance()方法。该方法也有3个参数。第一个参数产生代理对象的类加载器,第二个参数目标对象的接口数组,第三个参数就是实现InvocationHandler接口的类实例。

public interface UserManager {
    public void addUser(String userId, String userName);
}
public class UserManagerImpl implements UserManager {
    @Override
    public void addUser(String userId, String userName) {
        System.out.println("addUser(id:"+userId+",name:"+userName+")");
    }
}
public static void main(String[] args) {
         UserManager um=new UserManagerImpl(); 
         LogHandler log =new LogHandler(um); 
     um=ProxyUtil.proxyOne(um.getClass().getClassLoader(), 
                 um.getClass().getInterfaces(), log);
         
       TimeHandler time = new TimeHandler(um);
       um=ProxyUtil.proxyOne(um.getClass().getClassLoader(), 
                 um.getClass().getInterfaces(), time);
         
         um.addUser("1111", "张三");
    }

为了演示需要,这边又增加了一个LogHandler,跟TimeHandler代码一样。

CGLIB动态代理模拟

CGLIB动态代理的两个核心接口(类)分别是MethodInterceptor和Enhancer。是不是跟JDK动态代理很相似,用法也差不多。但CGLIB可以代理类和接口。注意:不能代理final类。

public class TimeInterceptor implements MethodInterceptor {
    private Object target;  
    public TimeInterceptor(Object target) {
        this.target = target;
    }
    @Override
    public Object intercept(Object proxy, Method method, 
            Object[] args, MethodProxy invocation) throws Throwable {
        System.out.println("方法之前:"+System.currentTimeMillis());
        Object ret = invocation.invoke(target, args); 
        System.out.println("方法之后:"+System.currentTimeMillis());
        
        return ret;
    }
}

intercept方法4个参数。1.生成的代理类实例。2.被代理对象的方法引用。3.方法参数值数组。4.代理类对方法的代理引用。

public class ProxyUtil {
    @SuppressWarnings("unchecked")
    public static  T proxyOne(Class clz,MethodInterceptor interceptor){
        return (T)Enhancer.create(clz, interceptor);
    }
    }

Enhancer类是CGLib中的字节码增强器。

public class UserManage {
    public void addUser(String userId, String userName) {
        System.out.println("addUser(id:"+userId+",name:"+userName+")");
    }
}
public static void main(String[] args) {
        UserManage um = new UserManage();
        TimeInterceptor time = new TimeInterceptor(um);
        um = ProxyUtil.proxyOne(um.getClass(), time);
        um.addUser("111", "老王");
    }

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...