AOP-动态代理

AOP-JDK动态代理和Cglib动态代理

静态代理:
  • 由程序员自己创建代理类,在程序运行之前代理类的.class文件就已经生成了

  • 静态代理事先就知道要代理的是什么

  • 代理类持有被代理类对象的引用

  • 调用时,代理对象调用被调用代理对象的响应方法,可以在其前后额外的添加其他功能

动态代理:
  • 动态代理是在程序运行期间,通过反射机制动态的创建而成的
  • 动态代理事先不知道要代理的目标,只有在运行的时候才知道
代理模式与AOP的关系:
  • AOP采用代理模式来实现
  • 我们编写的业务对象就是被代理的对象,代理对象是在程序运行的时候由spring容器动态生成的
  • 当使用AOP的时候:
    • spring容器将目标对象拦截下来(已经持有对目标对象的引用了),为其加入通知的一些功能,再调用目标对象的原有方法.
    • 将生成的代理类放到spring容器中
    • 当我们要获取目标对象的bean的时候,实际上是获取的代理对象的bean
    • 在进行调用的时候,首先执行的是代理类的代码,再由代理类调用目标类的方法进行输出
静态代理举例:
  • 这里举一个租房的例子:代理类( 房产中介 ) , 被代理类( 房子主人 ) , 调用者( 租客 ),中介和房子主人通过房子联系在一起,所以我们先来一个房子的接口,然后这个房子有被出租的功能

    /**
     *中介与房子主人的关联点
     */
    public interface House {
        void letHouse(double money);
    }
    

    一个中介类:

    /**
     * 代理类
     */
    public class HouseProxy implements House{
    //    持有被代理类的引用
        private HouseMaster houseMaster;
    
        public HouseProxy(HouseMaster houseMaster) {
            this.houseMaster = houseMaster;
        }
        @Override
        public void letHouse(double money) {
            System.out.println("中介=>收到租客租房请求,租金收到:"+money);
            double newMoney=money-500;
            houseMaster.letHouse(newMoney);
            System.out.println("中介=>吃掉"+(money-newMoney)+"的代理费,感谢老板");
    
        }
    }
    

    一个房子主人类:

    public class HouseMaster implements House{
        @Override
        public void letHouse(double money) {
    
            System.out.println("房子主人=>收到租金:"+money);
        }
    }
    

    租客类:

    /**
     * 客户类,租客
     */
    public class Customer {
        public static void main(String[] args) {
            HouseMaster houseMaster = new HouseMaster();
            HouseProxy houseProxy = new HouseProxy(houseMaster);
            houseProxy.letHouse(2000.00);
        }
    }
    

    运行结果:

    中介=>收到租客租房请求,租金收到:2000.0
    房子主人=>收到租金:1500.0
    中介=>吃掉500.0的代理费,感谢老板
    

    由此可以看出,代理类给被代理类添加了一些功能,房子租金他涨价了500.

JDk动态代理
  • 目标类:实现了一个接口User,我们给这个类添加一个统计性能的功能

    /**
     * 目标类
     */
    public class UserImpl implements User {
        @Override
        public void addUser() {
            for (int i=0;i<1000;i++){
                System.out.print(","+i);
            }
            System.out.println();
        }
    }
    

    要给目标类添加的功能:

    /**
     * 给目标类对象添加功能
     */
    public class MonitorHandler implements InvocationHandler {
    
        //持有目标类的引用
        private Object target;
    
        public MonitorHandler(Object target) {
            this.target = target;
        }
        /**
         * @param o
         * @param method 目标类的方法
         * @param args  目标类方法的参数
         * @return
         * @throws Throwable
         */
        @Override
        public Object invoke(Object o, Method method, Object[] args) throws Throwable {
    
    //        统计目标类方法执行之前的时间
            long beforerTime=System.currentTimeMillis();
    //        执行目标类方法
            Object invoke = method.invoke(target, args);
    //        统计目标类方法执行之后的时间
            long afterTime=System.currentTimeMillis();
            System.out.println("方法"+method.getName()+"总共执行了"+(afterTime-beforerTime)+"毫秒");
    //返回目标类对象
            return invoke;
        }
    }
    

    返回代理对象:

    /**
     * 生成代理类
     */
    public class JdkProxy{
    
        public static Object createProxy(Object target){
    
    //        获得目标类的类加载器
            ClassLoader classLoader = target.getClass().getClassLoader();
    //        获得目标类的接口
            Class<?>[] interfaces = target.getClass().getInterfaces();
    //        给目标类添加功能
            MonitorHandler monitorHandler = new MonitorHandler(target);
    //        调用Proxy的newProxyInstance()方法获得一个代理对象
            Object proxyTarget = Proxy.newProxyInstance(classLoader, interfaces, monitorHandler);
            return proxyTarget;
        }
    }
    

    执行结果:

    ,0,1,2,3,4,5,6,.......
    方法addUser总共执行了16毫秒
    
Cglib动态代理:
  • 如果目标类没有实现接口呢?那么就会spring就会使用Cglib来生成动态代理.

  • 目标类:还是添加一个统计方法性能的功能

    /**
     * 目标类,没有实现接口
     */
    public class UserImpl{
        public void addUser() {
            for (int i=0;i<1000;i++){
                System.out.print(","+i);
            }
            System.out.println();
        }
    }
    

    要添加的功能:

    /**
     * 方法拦截器,给目标类添加功能,注意要导cglib的包,不要导错了
     */
    public class MethodMonitor implements MethodInterceptor {
    
        @Override
        public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            //前置处理
            long before=System.currentTimeMillis();
    
            //调用父类相应的方法
            Object result = methodProxy.invokeSuper(target, args);
    
            //后置处理
            long after=System.currentTimeMillis();
            System.out.println("方法:"+method.getName()+"执行了:"+(after-before)+"毫秒");
            return result;
        }
    }
    

    生成Cglib动态代理对象:

    /**
     * 返回代理类对象
     */
    public class CglibProxy {
    
        public static Object createCglibProxy(Object target){
    //        创建增强器
            Enhancer enhancer = new Enhancer();
    //        将目标类设置成父类
            enhancer.setSuperclass(target.getClass());
    //        设置方法拦截器
            enhancer.setCallback(new MethodMonitor());
    //        创建代理类对象
            Object cglibProxy = enhancer.create();
            return cglibProxy;
        }
    }
    

    测试类:

    public class CglibApp {
        public static void main(String[] args) {
            UserImpl user = new UserImpl();
            UserImpl cglibProxy = (UserImpl)CglibProxy.createCglibProxy(user);
            cglibProxy.addUser();
        }
    }
    

    结果:

    ,0,1,2,3,4,5,6,7,8,9....
    方法:addUser执行了:36毫秒
    
JDK动态代理与Cglib动态代理的区别:
  • JDK使用接口的方式实现动态代理
  • Cglib使用继承的方式实现动态代理
  • 性能:jdk1.8之前cglib动态代理性能更好,从执行时间上来看,jdk1.8之后jdk动态代理胜出.
  • spring默认是使用jdk动态代理生成代理类的,但是也支持cglic
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值