java设计模式(一)代理模式

一.静态代理

静态代理要求代理类和被代理类都实现相同的接口或继承同一个父类。具体思想为:在代理类中设置一个目标接口属性并提供以目标接口为参数的构造方法,同时实现目标接口。然后以多态的形式传入被代理对象,完成代理对象的创建。
优点:可以做到在不修改目标对象的功能前提下,对目标功能进行扩展,同时避免实际对象的业务逻辑对外暴露。
缺点:由于需要实现接口,所以代码冗杂,不易维护。

二.动态代理

动态代理主要有两种:JDK动态代理(接口代理)Cglib动态代理(子类代理)

1.JDK动态代理

JDK动态代理中代理类不一定需要实现目标接口,但是目标类必须实现目标接口。具体思想为:
a.通过java反射加载目标接口获取Class类对象。
b.再通过处理器句柄(InvocationHandler 接口)获取构造器。
c.接着以多态的形式将目标对象注入处理器句柄中。
d.再以此代理处理器句柄构造代理类对象实例,强转完成对目标接口的代理。

    @Test
    public void t() throws Exception{
    
    
        Subject realSubject = new RealSubject();
        System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"); 
        //1.0 获取代理类的类对象,主要设置相同的ClassLoader去加载目标类实现的接口Subject类
        Class<?> proxyClass = Proxy.getProxyClass(Client.class.getClassLoader(), new Class[]{
    
    Subject.class});
        //2.0 得到代理类后,就可以通过代理类的处理器句柄来得到构造器
        final Constructor<?> con = proxyClass.getConstructor(InvocationHandler.class);
        //3.0 获取具体执行方法的句柄处理器,目的通过构造器传入被代理目标类对象,注入到代理类处理器句柄中进行代理调用
        final InvocationHandler handler = new DynamicProxy(realSubject);
        //4.0 通过构造器创建代理类对象
        Subject subject = (Subject)con.newInstance(handler);
        //5.0 最后调用方法
        subject.hello("proxy");

注:此处DynamicProxy类实现了InvocationHandler 接口并且重写了invoke方法。
另外,JDK动态代理之所以只能实现对接口的代理是因为Java的单继承机制。代理类已经继承了java.lang.reflect.Proxy类并实现了我们传入的接口,java不允许多继承类但是允许多实现接口,故只能通过实现目标接口的方式来实现功能拓展。
优点:解决了静态代理中冗余的代理实现类问题。
缺点:不能代理没有实现接口的类。
参考链接:JDK动态代理原理解析

2.Cglib动态代理

Cglib动态代理通过底层的字节码增强技术实现对象的代理。具体思想为:通过继承被代理类创建代理子类,实现 MethodInterceptor 接口,拦截所有父类方法的调用,重写 intercept 方法,然后再通过Enhancer 类的回调方法完成动态代理。
优点:可以对没有实现接口的类也进行动态代理。
缺点:技术复杂一些…
注:正是由于Cglib动态代理是通过创建子类对象来实现的,所以Cglib不能对final关键字修饰的方法进行处理。

猜你喜欢

转载自blog.csdn.net/m0_46550452/article/details/106751119