AOP前置知识,代理

1 概念

# 代理模式:
		1 二十三种设计模式中的一种,属于结构型模式
		2 实现:当需要调用目标方法的时候,不直接调用目标方法,而是通过代理类间接调用
		3 好处
				让附加功能代码从目标方法中剥离出来----解耦
				集中附加功能代码,方便统一维护

2 代理

目标类

public interface Calculator {
    int add(int lnum,int rnum);
    int sub(int lnum,int rnum);
    int mul(int lnum,int rnum);
    int div(int lnum,int rnum);
}
public class Target implements Calculator {
    /**
     * 目标类:
     *   实现加减乘除
     */
    @Override
    public int add(int lnum, int rnum) {
        System.out.println("目标代码:(lnum + rnum)=" + (lnum + rnum));
        return lnum + rnum;
    }
    @Override
    public int sub(int lnum, int rnum) {
        System.out.println("目标代码:(lnum - rnum)=" + (lnum - rnum));
        return lnum - rnum;
    }
    @Override
    public int mul(int lnum, int rnum) {
        System.out.println("目标代码:(lnum * rnum)=" + (lnum * rnum));
        return lnum * rnum;
    }
    @Override
    public int div(int lnum, int rnum) {
        System.out.println("目标代码:(lnum / rnum)=" + (lnum / rnum));
        return lnum / rnum;
    }
}

静态代理类

  • 一个目标类对应一个静态代理类
public class ProxyCla implements Calculator{
    /**
     *静态代理:
     *  一个目标类对应一个静态代理类
     */
    Target target=new Target();
    @Override
    public int add(int lnum, int rnum) {
        System.out.println("日志_参数:=====>"+lnum+","+rnum);
        int res = target.add(lnum, rnum);
        System.out.println("日志_结果:=====>"+res);
        return res;
    }
    @Override
    public int sub(int lnum, int rnum) {
        System.out.println("日志_参数:=====>"+lnum+","+rnum);
        int res = target.sub(lnum, rnum);
        System.out.println("日志_结果:=====>"+res);
        return res;
    }
    @Override
    public int mul(int lnum, int rnum) {
        System.out.println("日志_参数:=====>"+lnum+","+rnum);
        int res = target.mul(lnum, rnum);
        System.out.println("日志_结果:=====>"+res);
        return res;
    }
    @Override
    public int div(int lnum, int rnum) {
        System.out.println("日志_参数:=====>"+lnum+","+rnum);
        int res = target.div(lnum, rnum);
        System.out.println("日志_结果:=====>"+res);
        return res;
    }
}

静态代理类测试结果

日志_参数:=====>11
目标代码:(lnum + rnum)=2
日志_结果:=====>2
日志_参数:=====>3-1
目标代码:(lnum - rnum)=4
日志_结果:=====>4
日志_参数:=====>2525
目标代码:(lnum * rnum)=625
日志_结果:=====>625
日志_参数:=====>1204
目标代码:(lnum / rnum)=30
日志_结果:=====>30

静态代理的弊端

静态代理确实实现了 代理模式的目标----解耦
静态代理的代码是写死的:
	1 静态代理类实现和目标类同样的借口,导致一个目标类需要一个静态代理类
	2 静态代理类中的目标对象也是写死的
	
导致的后果:
	产生大量重复的代码,附加功能代码还是分散的,并没有实现对附加代码的统一管理

JDK动态代理

通过JDK 提供的 API   在程序运行的过程中,动态得去生成每一个目标类所对应的动态代理类
java.lang.reflect.Proxy类提供了为对象产生代理对象的方法

请添加图片描述

三大参数

# 参数1 classloder 类加载器
		为什么需要指定类加载器?
			 答:动态代理的作用就是在程序的运行过程中动态的生成 目标类的 动态代理类,生成完毕之后类需要加载。
		类加载器有哪几种
			 答:
			 		1 根类加载器
			 				底层是使用C实现,加载核心类库
			 		2 扩展类加载器
			 				加载扩展类库
			 		3 应用类加载器
			 				加载 自己写的类库、第三方类库
		如何获取类加载器:
			 答:通过反射获取,获取Class字节码文件对象,在通过其获取类加载器
# 参数2 Class[ ] interfaces 实现的所有接口
		原则:目标类和代理类需要实现相同的接口
		  答:参数2就是来获取目标对象实现的所有接口的Class字节码对象数组
	
# 参数3 InvocationHandler接口    -------执行处理
			答:定义代理类中抽象方法的重写细节,即附加代码编写的地方。使用匿名内部类写附加代码。
			答:一共三个部分:
					1 proxy   表示代理对象
					2 method  表示要执行的方法
					3 args    表示要执行的方法的参数列表
			

工厂类:动态生成代理类对象

public class ProxyFactory {
    private Object target;
    public ProxyFactory(Object target){
        this.target=target;
    }
    public Object getProxy(){
        /**
         * JDK代理三大参数:
         * ClassLoader,Class[] interfaces,InvocationHandler
         */
        return java.lang.reflect.Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("动态代理日志:==========>:操作名:"+method.getName()+",参数:"+ Arrays.toString(args));
                        Object res = method.invoke(target, args);
                        System.out.println("动态代理日志:==========>:结果:"+res);
                        retur![在这里插入图片描述](https://img-blog.csdnimg.cn/4c9fbb962bab4aa18b489a590bd832c6.png#pic_center)
n res;
                    }
                }
        );
    }
}

JDK动态代理测试结果

@SpringBootTest
class ProxydemoApplicationTests {
    @Test
    void contextLoads() {
        ProxyFactory proxyFactory = new ProxyFactory(new Target());
        Calculator proxy =(Calculator) proxyFactory.getProxy();
        proxy.add(1,1);
        proxy.sub(4,-1);
        proxy.mul(25,27);
        proxy.div(120,3);
    }
}
动态代理日志:==========>:操作名:add,参数:[1, 1]
目标代码:(lnum + rnum)=2
动态代理日志:==========>:结果:2
动态代理日志:==========>:操作名:sub,参数:[4, -1]
目标代码:(lnum - rnum)=5
动态代理日志:==========>:结果:5
动态代理日志:==========>:操作名:mul,参数:[25, 27]
目标代码:(lnum * rnum)=675
动态代理日志:==========>:结果:675
动态代理日志:==========>:操作名:div,参数:[120, 3]
目标代码:(lnum / rnum)=40
动态代理日志:==========>:结果:40

cglib动态代理和JDK动态代理的区别

1 JDK动态代理,要求必须有借口,最终生成的代理类在,com.sun.proxy包下
	类名为:$proxy2($proxy+数字,此处以2示范)
  除此之外,JDK动态代理,生成的动态代理类和目标类实现相同的接口

2 cglib动态代理,没有要求,最终生成的代理类有两大特性:
  		cglib动态代理生成的代理类会继承目标类
  		cglib动态代理生成的代理类和目标类在同一个包下

Proxy增强Target的地方

# 1 方法调用前
# 2 方法调用后
# 3 异常发生时
# 4 finally代码中

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值