spring 动态代理模式

  • 代理模式
为某一个对象(委托类)提提供一个代理(代理类),用来控制这个对象的访问。委托类和代理类有一个共同的父类或父接口。代理类会对请求做预处理、过滤,将请求分配给指定对象

代理模式在java开发中是一种比较常见的设计模式。设计目的旨在为服务类和客户类之间插入其他功能,插入的功能对于调用者是透明的,起到伪装控制的作用。
如住房的例子:房客、中介、房东;对应于代理模式中即:客户类、代理类、委托类(类代理类)
  • 代理模式设计原则
代理类 和 委托类 具有相似的行为(共有)
代理类 增强 委托类的行为
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c6CM9LFe-1650266348261)(image/代理模式.png)\]](https://img-blog.csdnimg.cn/ec26b6e0ddaa433a97e266a887695721.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aS05Y-R5Zyo6aOO5Lit5ZOt5rOj,size_15,color_FFFFFF,t_70,g_se,x_16)

静态代理

某个对象提供一个代理,代理角色固定,以控制对这个对象的访问。代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。
代理类负责请求的预处理、过滤,将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
  • 静态代理 提供父类或父接口
public interface RentHouse {

    public void toRentHouse();
}
  • 目标类
public class You implements RentHouse{
    @Override
    public void toRentHouse() {
        System.out.println("目标对象,租到房子");
    }
}
  • 代理类
/**
 * 1. 实现行为
 * 2. 增强目标对象行为
 * */
public class AgencyProxy implements RentHouse{

    //目标对象
    private RentHouse rentHouse;
    //有参构造函数,传入目标对象
    public AgencyProxy(RentHouse rentHouse) {
        this.rentHouse = rentHouse;
    }

    @Override
    public void toRentHouse() {
        System.out.println("中介找房");
        rentHouse.toRentHouse();
        System.out.println("中介收钱");
    }
}
  • 测试类
public class com.zh.starter.StarterProxy {
    public static void main(String[] args) {
        AgencyProxy proxy = new AgencyProxy(new You());
        proxy.toRentHouse();
    }
}
  • 测试结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KF4pF1hD-1650266348262)(image/静态代理.png)]

动态代理

相比于静态代理,动态代理在创建代理对象上更加灵活,动态代理类的字节码在程序运行时,由Java反射机制动态产生。
它会根据需要,通过反射机制在程序运行期,动态的为目标对象创建代理对象,无需程序员手动编写源码。动态代理不仅简化了编程工作,
而且提高了软件系统的可扩展性,因为反射机制可以生成任意类型的动态代理类。代理的行为可以代理多个方法,即满足产生需要的同时又达到代码通用的的目的。
  • 动态代理特点
1. 目标对象不固定
2. 在应用程序执行时动态创建目标对象
3. 代理对象会增强目标对象的行为

JDK动态代理

需要使用JDK动态代理的类,必须要有接口实现
  • newProxyInstance
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下操作方法
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
  • 理解
返回一个指定接口的代理类的实例方法调用分派到指定的调用处理程序,(返回代理对象)

    loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象加载
    
    interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,
        那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法
        
    h:一个InvocationHandler接口,表示代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,
        将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法(传入InvocationHandler接口)
  1. 定义RentHouse接口和两个抽象方法
public interface RentHouse {

    public void toRentHouse();

    public String toRentHouse2(String name);
}
  1. 定义目标类,实现接口,重写方法
public class You implements RentHouse{
    @Override
    public void toRentHouse() {
        System.out.println("目标对象,租到房子");
    }

    @Override
    public String toRentHouse2(String name) {
        System.out.println(name+"目标对象,租到房子");
        return "result01";
    }
}
  1. 定义JDK动态 代理类
public class JdkDynamicProxy {

    //目标对象
    private Object target;
    
    //带参构造传递目标对象
    public JdkDynamicProxy(Object target) {
        this.target = target;
    }

    /**
     * 得到代理对象
     * */
    public Object getProxy(){
        Object object = null;
        /**
         * 通过调用Proxy代理类中的静态方法 newProxyInstance(),得到代理对象
         * */

        //定义了由哪个ClassLoader对象来生成的代理对象进行加载
        ClassLoader classLoader = this.getClass().getClassLoader();
        //要代理的对象提供一组什么接口
        Class[] interfaces = target.getClass().getInterfaces();
        
        //一个InvocationHandler接口,表示代理实例的调用处理程序实现的接口
        InvocationHandler invocationHandler = new InvocationHandler() {
            /**
             * 注:当代理对象被调用时 invoke方法会被调用一次
             * 
             * Object 代理对象
             * Method 目标对象方法
             * Object[] 目标方法需要的参数
             * */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println(method.getName());//toRentHouse
                System.out.println(args.length);
                System.out.println(args[0]);
                System.out.println("invoke...调用");

                /**
                 *  反射 invoke方法 调用目标对象方法
                 *  方法名.invoke(对象,方法需所需参数)
                 * */
                Object result = method.invoke(target, args);

                System.out.println("result:"+result);
                return result;
            }
        };

        //调用方法,得到代理对象
        object = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);

        return object;
    }
}
  1. 测试类
public class com.zh.starter.StarterJdkDynamicProxy {
    public static void main(String[] args) {
        //目标对象有返回值
        RentHouse target2 = new You();
        //动态代理类对象
        JdkDynamicProxy jdkDynamicProxy2 = new JdkDynamicProxy(target2);
        //得到代理对象
        RentHouse object2 = (RentHouse) jdkDynamicProxy2.getProxy();
        //代理对象调用
        object2.toRentHouse2("张三");

    }
  1. 结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OLtnt0QQ-1650266348263)(image/JDK动态代理测试.png)]

CGLIB 动态代理

继承思想,代理类是目标类的子类,代理类对目标类中的方法进行重写

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

    public void toMarry(){
        System.out.println("结婚了");
    }
}
  1. 定义CglibDynamicProxy 动态代理类
public class CglibProxy {

    //目标对象
    private Object target;

    //通过带参构造器 获取目标对象
    public CglibProxy(Object target) {
        this.target = target;
    }

    /**
     * 获取代理对象
     *
     * */
    public Object getProxy(){
        //通过Enhancer对象的create()方法可以生成一个类,用于生成代理对象
        Enhancer enhancer = new Enhancer();
        //设置当前类的父类(将目标类作为代理类父类)
        enhancer.setSuperclass(target.getClass());
        //定义 方法拦截器
        MethodInterceptor interceptor = new MethodInterceptor() {
            /**
             * 代理过程 当代理对象调用方法时 intercept()方法会被执行
             * o 由CGLIB动态生成的代理类实例
             * method 目标方法
             * objects 方法所需要的参数
             * methodProxy 代理对象对方法的引用
             * */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("CGLIB...指定方法执行前");
                Object result = method.invoke(target, objects);
                System.out.println("CGLIB...指定方法执行后");
                return result;
            }
        };

        //设置拦截过程(调用目标对象的方法、增强用户行为)
        enhancer.setCallback(interceptor);

        //生成一个类
        return enhancer.create();
    }
}
  1. 测试
public class CglibTest {
    public static void main(String[] args) {
        
        //目标对象
        User user = new User();
        //代理类
        CglibProxy cglibProxy1 = new CglibProxy(user);
        //代理对象
        User user1 = (User) cglibProxy1.getProxy();
        //调用
        user1.toMarry();
    }
}
  1. 测试结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5TwQLCed-1650266348263)(image/Cglib动态代理测试.png)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值