JAVA动态代理

动态代理

静态代理

静态代理是由业务实现类、业务代理类两部分组成。业务实现类负责实现组主要的业务方法,业务代理类负责对调用的业务方法进行拦截、过滤、预处理,主要是在方法中首先进行预处理动作,然后调用业务实现类的方法,还可以规定调用后的操作。我们在需要调用业务时,不是直接通过调用业务实现类来调用的,而是通过业务代理类的同名方法来调用被代理类处理过的方法。

代码实现:

定义接口:Subject.class

public interface Subject {

    public void request();

}

业务实现类:SubjectImpl.java

public class SubjcetImpl implements Subject{

    @Override
    public void request() {
        System.out.println("真实请求");
    }

}

代理类:ProxySubjcet.java

public class ProxySubject implements Subject {

    private SubjcetImpl subjectImpl;

    public ProxySubject(SubjcetImpl subjectImpl) {
        this.subjectImpl = subjectImpl;
    }

    @Override
    public void request() {
        System.out.println("调用前,进行操作");
        subjectImpl.request();
        System.out.println("调用后,进行操作");
    }

}

使用代理类 Main.java

    public static void main(String[] args) {
        ProxySubject proxySubject = new ProxySubject(new SubjcetImpl());
        proxySubject.request();
    }

静态代理的缺点很明显:一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就需要定义很多实现类和代理类才可以。

如果代理类对业务方法的预处理、调用操作都一样的话,那对多个代理类就会出现很多重复的代码、

JDK动态代理

JDK动态代理所用到代理类在程序调用对象是才有JVM真正创建,JVM根据传进来的业务实现类对象一级方法名、动态地创建了一个代理类的class文件并被子解码引擎执行,然后通过该代理类对象进行方法丢调用。

定义业务接口及定义业务实现类,见上面静态代理的业务接口及业务实现类

实现 调用管理接口InvocationHandler,创建动态代理类

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

/**
 * 调用自定义的代理hander的构造器来获取代理对象实例
 *
 * @author houzhengming
 */
public class DynamicProxyHandler implements InvocationHandler {
    // 这其实业务实现类对象,用来调用具体的业务方法 
    private Object object;

    public DynamicProxyHandler(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理运行前" + method.getName());
        Object result = method.invoke(object, args);
        System.out.println("代理运行后");
        return result;
    }
}

执行 Main.java

    public static void main(String[] args) {

        //创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
        Subject subject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new Class[]{Subject.class},
                new DynamicProxyHandler(new SubjcetImpl()));
        subject.request();

    }

优化:

定义接口应用(使用向上转型),并用代理对象绑定业务实现类对象,

修改为:

/**
 * @author houzhengming
 */
public class MyInvocationHandler implements InvocationHandler {

    private Object object;

    public MyInvocationHandler(Object object) {
        this.object = object;
    }

    public  T bind() {
        Object proxy = Proxy.newProxyInstance(this.object.getClass().getClassLoader(),
                this.object.getClass().getInterfaces(),
                this);
        return (T) proxy;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开始执行");
        Object o = method.invoke(object, args);
        return o;
    }
}

执行:

    public static void main(String[] args) {
        Subject subject = new MyInvocationHandler(new SubjcetImpl()).bind();
        subject.request();
    }

JDK动态代理的代理对象在创建是,需要业务实现类所在的接口作为参数(因为后面代理方法时需要根据接口的方法名进行调用),如果业务实现类是没有实现接口而是直接定义业务方法的话,就无法使用JDK动态代理了,并且在业务实现类中新增了业务接口中没有打方法,这些方法也是无法被动态代理的(因为无法调用)。

CGLIB动态代理

cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中的业务方法实现代理。因为采用的是继承,所有不能对final修饰的类进行代理

直接定义业务类,SubjectImpl.java

    public static void main(String[] args) {

        SubjectImpl subjectImpl = (SubjectImpl) new MyMethodsInterceptor().getInstance(new SubjectImpl());
        subjectImpl.request();
    }

实现MethodInterceptor方法代理接口,创建代理类

/**
 * 自定义实现cglib中的methodInterceptor
 */
public class MyMethodsInterceptor implements MethodInterceptor {

    /**
     * 业务对象
     */
    private Object target;

    /**
     * 获取动态代理中的示例,类似于JDK中的动态代理的绑定
     * @param target
     * @return
     */
    public Object getInstance(Object target) {
        // 业务对象赋值
        this.target = target;
        // 创建加强器,用来创建代理类
        Enhancer enhancer = new Enhancer();
        // 为加强器指定要代理的类,即为下面要生成的代理类指定父类
        enhancer.setSuperclass(this.target.getClass());
        // 设置回调,对于代理类上所有的方法的回调,都会调用callback。而callback需要实现intercept
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }

    /**
     * 实现回调方法
     * @param o
     * @param method
     * @param objects
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用操作前");
        //调用业务类的父类
       Object o1=  methodProxy.invokeSuper(o,objects);
        System.out.println("调用操作后,方法执行结果为:"+o1);
        return o1;
    }

}

调用:Main.java

通过代理类对象.getInstance(业务对象)返回一个动态代理类对象(它是业务类的子类。可以用业务类引用指向它)。通过动态代理类对象进行方法引用。

    public static void main(String[] args) {

        SubjectImpl subjectImpl = (SubjectImpl) new MyMethodInterceptor().getInstance(new SubjectImpl());
        subjectImpl.request();
    }

比较

静态代理是通过在代码中显式定义一个业务实现类,一个代理,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法。

JDK动态代理是通过接口的方法名,在动态生成的代理类中调用业务实现类的同名方法。

CGLIB动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法实现的。、

你可能感兴趣的:(JAVA动态代理)