目前Java动态代理的实现分为两种
- 基于JDK 的动态代理(基于接口的动态代理技术)
- 基于CGLIB的动态代理(基于父类的动态代理技术)
在业务中使用动态代理,一般是为了给需要实现的方法添加预处理或者添加后续操作,但是不干预实现类的正常业务,把一些基本业务和主要的业务逻辑分离。我们一般所熟知的Spring的AOP原理就是基于动态代理实现的。
基于JDK的动态代理
基于JDK的动态代理就需要了解两个类:1.InvocationHandler(接口)、2.Proxy(类)
下面我们借助这两个类,通过代码来讲解一下
//1.创建一个接口
public interface Subject {
void hello(String param);
}
//2.创建接口的实现类
public class SubjectImpl implements Subject {
@Override
public void hello(String param) {
System.out.println("hello " + param);
}
}
//3.创建SubjectImpl的代理类
public class SubjectProxy implements InvocationHandler {
private Subject subject;
public SubjectProxy(Subject subject) {
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("--------------begin-------------");
Object invoke = method.invoke(subject, args);
System.out.println("--------------end-------------");
return invoke;
}
}
//4.编写代理类实际的调用,利用Proxy类创建代理之后的Subject类
public class Main {
public static void main(String[] args) {
Subject subject = new SubjectImpl();
InvocationHandler subjectProxy = new SubjectProxy(subject);
Subject proxyInstance = (Subject) Proxy.newProxyInstance(subjectProxy.getClass().getClassLoader(), subject.getClass().getInterfaces(),subjectProxy);
proxyInstance.hello("world");
}
}
//输出:
//--------------begin-------------
//hello world
//--------------end-------------
//看这个结果,实际上在Subject类中只会输出一条hello world,
//但是在被代理之后,实际调用的方法是SubjectProxy的invoke方法,
//这样可以在不修改业务类的情况下对业务类增加一些日志等其他操作,
//甚至可以直接修改有返回值方法的返回值。
方法说明:
基于CGLIB的动态代理
因为基于JDK的动态代理一定要继承一个接口,而绝大部分情况是基于POJO类的动态代理,那么CGLIB就是一个很好的选择,在Hibernate框架中PO的字节码生产工作就是靠CGLIB来完成的。还是先看代码。
//1.引入CGLIB的jar包
//2.创建代理类
public class CGsubject {
public void sayHello(){
System.out.println("hello world");
}
}
<!--如果直接对这个类创建对象,那么调用sayHello方法,
控制台就会输出hello world,现在我们还是要对输出添加前置和后置的log输出。
来打印输出前和输出后的时间。-->
//3.实现MethodInterceptor接口,对方法进行拦截处理。
public class HelloInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("begin time -----> "+ System.currentTimeMillis());
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("end time -----> "+ System.currentTimeMillis());
return o1;
}
}
//4.创建被代理类
public class Main {
public static void main(String[] args) {
//创建增强器
Enhancer enhancer = new Enhancer();
//设置父类(目标)
enhancer.setSuperclass(CGsubject.class);
//设置回调
enhancer.setCallback(new HelloInterceptor());
//创建代理对象
CGsubject cGsubject = (CGsubject) enhancer.create();
cGsubject.sayHello();
}
}//利用Enhancer来生产被代理类,这样可以拦截方法,对方法进行前置和后置log的添加。
//输出:
//begin time -----> 1534836443741
//hello world
//end time -----> 1534836443786
方法说明: