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