静态代理与动态代理(JDK、CGLIB)
问题引入
- 什么是静态代理?
- 什么是动态代理?
- 静态代理和动态代理的区别是什么?
- JDK动态代理和CGLIB动态代理的区别?
静态代理
主要是通过代码的业务来处理,在编译之前就已经处理好。
例子
先创建目标类
/** * Created on 2018/6/6 * 创建目标类接口 * @author wang.teng */
public interface BusiInterface {
void execute();
}
/** * Created on 2018/6/6 * 目标类接口的实现 * @author wang.teng */
public class BusiInterfaceImpl implements BusiInterface {
@Override
public void execute() {
System.out.println("处理业务");
}
}
在创建代理类:
/** * Created on 2018/6/6 * 代理类,对目标的执行以及前置后置处理 * @author wang.teng */
public class Proxy implements BusiInterface{
BusiInterface busiInterface;
Proxy(BusiInterface busiInterface){
this.busiInterface =busiInterface;
}
@Override
public void execute() {
before();
busiInterface.execute();
after();
}
public static void before() {
System.out.println("前置处理");
}
public static void after() {
System.out.println("后置处理");
}
}
优点:
在不修改目标类的情况下可以对目标类进行拦截和拓展。
缺点:
代理类需要实现目标类接口,所以每个目标类都得相对有一个代理类,耦合性太强,目标类增加方法则代理类也得进行实现。
动态代理
JDK动态代理
动态代理是通过反射类拿到目标类的接口实现,进行拦截和拓展。
目标类和接口实现同上面的静态代理,主要不同的地方是代理类的实现,代理类主要是通过反射,拿到目标类的接口的实现,来获取目标类对象,再目标类执行方法的时候进行拦截。
/** * Created on 2018/6/6 * JDK动态代理类 * @author wang.teng */
public class DynamicProxy {
public Object getProxyInstance(BusiInterface busiInterface){
return Proxy.newProxyInstance(
busiInterface.getClass().getClassLoader()
busiInterface.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前拦截...");
Object invoke = method.invoke(busiInterface, args);
System.out.println("后拦截...");
return invoke;
}
});
}
}
优点:
可以不用实现目标类的接口,直接通过反射拿到目标的方法进行拦截。
缺点:
目标类对象一定要实现接口
CGLIB代理
是通过字节码创建子类的方式,并在子类中采用方法拦截拦截父类所有的方法,进行切入。CGLIB可以代理没有接口的类。
例子:
先引入cglib包:
compile group: 'cglib', name: 'cglib', version: '2.2.2'
目标类:
/** * Created on 2018/6/7 * 没有接口的对象类 * @author wang.teng */
public class Business {
public void execuate(){
System.out.println("do something !");
}
}
代理类:
/** * Created on 2018/6/7 * * @author wang.teng */
public class CglibProxy implements MethodInterceptor {
public Object getProxy(Class clazz){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz); //设置父类
enhancer.setCallback(this); //设置回调
return enhancer.create(); //创建子类
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("前置交易");
Object invokeSuper = methodProxy.invokeSuper(o, objects);
System.out.println("后置交易");
return invokeSuper;
}
}
/** * Created on 2018/6/7 * * @author wang.teng */
public class Test {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
Business business = (Business) proxy.getProxy(Business.class);
business.execuate();
}
}
优点:
可以代理类和接口,在执行效率比较高
缺点:
虽说在代理执行上效率比较高,但是在创建对象上,要使用字节码来进行创建对象,耗时会比JDK久很多。对于final修饰的方法是无法进行代理的。