【搞定spring 原理分析】 第一篇 spring AOP实现原理

https://www.cnblogs.com/puyangsky/p/6218925.html

目录

 

代理模式

代理类实现了被代理类的接口,同时与被代理类是组合关系。

一、静态代理 

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成

二、动态代理

JDK自带方法:最核心的是java.lang.reflect包中的 : InvocationHandler调用处理器接口和Proxy.newProxyInstance方法:

1、代理类由Java API创建,我们只需要直接用Proxy类的newProxyInstance方法返回有一个被代理类的代理类即可【Proxy.newProxyInstance返回一个代理类】

2、调用代理类的方法时实质是转发调用处理器进行处理InvocationHandler h处理,【代理类会自己去调用invoke方法,此方法拥有被代理类,被代理类的方法(代理类.show(),所以能知道这次调用的是什么方法),以及调用方法的参数】

3、例子

4、“动态代理是不是指运行时才将它实例话并和handler联系起来

三、CGLIB库的方法?


代理模式

代理模式的UML类图如下:

代理类实现了被代理类的接口,同时与被代理类是组合关系。

下面看一下代理模式的实现。

一、静态代理 

package test;

class pear implements Fruit{
    @Override
    public void show() {
        System.out.println("我是被代理的类");
    }
}

public class staticAgent implements Fruit{
    private Fruit proxy; //用的组合

    public staticAgent(Fruit proxy){
        this.proxy = proxy;
    }

    @Override
    public void show() {
        System.out.println("before method");
        this.proxy.show();
        System.out.println("after method");
    }

    //测试
    public static void main(String[] args) {
        staticAgent agent = new staticAgent(new pear());
        agent.show();
    }
}

结果:

before method
我是被代理的类
after method

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成

二、动态代理

 

JDK自带方法:最核心的是java.lang.reflect包中的 : InvocationHandler调用处理器接口和Proxy.newProxyInstance方法:

  • 1、代理类由Java API创建,我们只需要直接用Proxy类的newProxyInstance方法返回有一个被代理类的代理类即可【Proxy.newProxyInstance返回一个代理类】

public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException

其中的参数含义如下:

  • loader:被代理的类的类加载器
  • interfaces:被代理类的接口数组
  • invocationHandler:就是刚刚介绍的调用处理器类的对象实例

该方法会返回一个被修改过的类的实例,从而可以自由的调用该实例的方法

 

  • 2、调用代理类的方法时实质是转发调用处理器进行处理InvocationHandler h处理,【代理类会自己去调用invoke方法,此方法拥有被代理类,被代理类的方法(代理类.show(),所以能知道这次调用的是什么方法),以及调用方法的参数】

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

我们对于被代理的类的操作都会由该接口中的invoke方法实现,其中的参数的含义分别是:

  • proxy:被代理的类的实例
  • method:调用被代理的类的方法
  • args:该方法需要的参数

使用方法首先是需要实现该接口,并且我们可以在invoke方法中调用被代理类的方法并获得返回值,自然也可以在调用该方法的前后去做一些额外的事情,从而实现动态代理,下面的例子会详细写到。

  • 3、例子

接口:

package test;

public interface Fruit {
    public void show();
}
package codeTest.Dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JdkProxyFactory {
    // 创建代理
    public static Object createProxy(Object target){
        // 三个参数: 被代理类的类加载器、 被代理类的实现接口、 invocationhandler
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new MyHander(target));
    }


    static class MyHander implements InvocationHandler{

        private Object target ;
        public MyHander(Object target){
            this.target = target;
        }

        //每次proxy的方法被调用【通过代理类调用它的方法】,就会导致proxy调用此方法
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("beforeMethod>>>>"+ proxy.getClass().getName());
            Object ret = method.invoke(target,args);
            System.out.println("afterMethod>>>>");
            return ret;
        }
    }

}

class Test{
    public static void main(String[] args) {
        Fruit apple = (Fruit) JdkProxyFactory.createProxy(new Apple());
        apple.show();
        Fruit pear = (Fruit) JdkProxyFactory.createProxy(new pear());
        pear.show();

        System.out.println(apple.getClass().getName()==pear.getClass().getName()); //true
    }
}

  • 结果
beforeMethod>>>>com.sun.proxy.$Proxy0
我是被代理的类__Apple
afterMethod>>>>
beforeMethod>>>>com.sun.proxy.$Proxy0
我是被代理的类__pear
afterMethod>>>>
true

4、“动态代理是不是指运行时才将它实例话并和handler联系起来

答:不是的,动态代理之所以被称为动态,是因为运行时才将它的类创建出来,代码开始时,还没有proxy类,它是根据需要从你传入的接口集创建的。

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。 

静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。 
动态代理:在程序运行时,运用反射机制动态创建而成。 

三、CGLIB库的方法?

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 

public class CglibProxyFactory implements MethodInterceptor {  
    // 被代理目标对象  
    private Object target;  
  
    // 在构造工厂时传入被代理对象  
    public CglibProxyFactory(Object target) {  
        this.target = target;  
    }  
  
    // 创建代理对象方法  
    public Object createProxy() {  
        // 1、 创建Enhancer对象  
        Enhancer enhancer = new Enhancer();  
  
        // 2、 cglib创建代理,对目标对象,创建子类对象  
        enhancer.setSuperclass(target.getClass());  
  
        // 3、传入 callback对象,对目标增强  
        enhancer.setCallback(this);  
  
        return enhancer.create();  
    }  
  
    @Override  
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {  
        System.out.println("记录日志......");  
        // 按照JDK编程  
        return method.invoke(target, args);  
    }  
}  

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全评估测试题大模型安全评估测试题关键词库生成内容测试题库应拒答测试题库非拒答测试题大模型安全
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值