1

jdk动态代理推荐看这篇文章
https://www.jianshu.com/p/4e1...

一.什么是代理模式

代理模式是设计模式中最常见的一种。当目标类不方便操作时,这时用另一个类代替目标类执行相同的操作。
意图:不改变原目标类的前提下,提供额外的功能,扩展目标对象的功能。

二.静态代理和动态代理
静态代理:编译期目标类,代理类,接口都已经生成class文件。
当我们要改变已有的代码时,有两种方式。1),直接在原始代码上修改,但是这种不符合扩展开放,修改关闭的原则。
2)增加代理类,通过静态代理即可实现。
3)比如要在原始的方法前后打印耗时日志,我们可以使用代理类实现这个功能。目标类和代理类实现相同的接口,在代理类中将目标类的对象作为属性,然后调用原来的方法。同时可以加入修改的代码。

//接口
public interface Image {
    
    void display();    
}

//代理类
public class ProxyImage implements Image {

    private RealImage realImage;//目标类的对象
    
    public ProxyImage(RealImage realImage) {
        this.realImage = realImage;
    }
    
    @Override
    public void display() {
        
        long startTime = System.currentTimeMillis();
        realImage.display();
        long endTime = System.currentTimeMillis();
        System.out.println("执行display方法耗时:"+(endTime-startTime));
    }
}

//目标类
public class RealImage implements Image {

    @Override
    public void display() {
        System.out.println("开始显示图片");        
    }
}
//测试 不改变原来的逻辑,又添加了新的功能
public class Test {

    public static void main(String[] args) {
        RealImage realImage = new RealImage();
        ProxyImage proxyImage = new ProxyImage(realImage);
        proxyImage.display();
    }
}

动态代理:代理类在程序运行过程中被创建。动态代理的优势在于可以很方便的对目标类的函数进行统一的处理。而不是修改目标类中的每个方法。分为JDK动态代理和CGlib动态代理,
1)JDK动态代理:又称为基于接口的代理
java.lang.reflect.Proxy:生成动态代理对象;
java.lang.reflect.InvocationHandler 处理器接口;
(1)定义一个处理器类,实现invocationHandler接口,并重写invoke方法。
(2)代理类实现和目标类相同的接口//自动实现
(3)调用Proxy.newProxyInstance(...)生成一个代理实例。
(4)通过代理实例调用方法

//接口
public interface Subject {
    
    int sellBooks();        
}
//目标类
public class RealSubject implements Subject {
    @Override
    public int sellBooks() {
        System.out.println("卖书");        
        return 1;
    }    
}
//自定义处理器,每一个代理类对象都对应一个处理器
public class MyInvocationHandler implements InvocationHandler {

    Subject realSubject;
    
    public MyInvocationHandler(Subject realSubject) {
        this.realSubject = realSubject;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("调用代理类");        
        int count = (int)method.invoke(realSubject, args);//执行目标类的方法
        System.out.println("调用的是卖书的方法");
        return count;
    }
}
//
public class Test{
    
    public static void main(String[] args) {
        Subject realSubject = new RealSubject();        
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(realSubject);
        Class cls = realSubject.getClass();
        
        Subject proxyClass = (Subject)Proxy.newProxyInstance(cls.getClassLoader(),
cls.getInterfaces(), myInvocationHandler);
        proxyClass.sellBooks();        
    }    
}

在测试类中通过Proxy类的静态方法获取代理类对象,其中三个参数,一个是类加载器(目标类),目标类实现的接口,处理器对象。程序运行过程中动态产生代理对象。当执行sellBooks方法时,实际会执行MyInvocationHandler中的invoke方法,通过反射执行目标类的方法。在执行目标方法前后,我们可以做一些处理,增强功能。

2)CGlib动态代理:目标类生成子类实现代理,子类执行方法时会被拦截器拦截,在拦截器中的interceptor方法中,通过反射执行目标方法,这样在目标方法前后我们可以做一些自定义的处理。 如果是private或者final修饰的方法,则不会被重写。
CGlib是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理。SpringAOP中默认使用jdk动态代理,如果目标对象没有实现接口,则使用cglib动态代理

public class Engineer {

    //可以被代理
    public void eat() {
        System.out.println("工程师正在吃饭");
    }
    
    //不能被生成的子类重写
    public final void work() {
        System.out.println("工程师正在工作");
    }
    
    //不能被生成的子类重写
    private void play() {
        System.out.println("the engineer is playing game");
    }
}

public class CglibProxy implements MethodInterceptor {

    private Object target;
    
    public CglibProxy(Object target) {
        this.target = target;
    }
    
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("cglib动态代理被调用");
        Object result = method.invoke(target, objects);        
        return result;
    }
    
    public static Object getProxy(Object target) {
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置拦截器
        enhancer.setCallback(new CglibProxy(target));
        //生成代理类对象
        return enhancer.create();
    }
}

public class TestCglib {
    
    public static void main(String[] args) {
        
        //获取代理类实例
         Engineer proxyEngineer = (Engineer)CglibProxy.getProxy(new Engineer());
         proxyEngineer.eat();
    }
}

forest
0 声望1 粉丝

« 上一篇
java反射