一、基于JDK的代理增强
实现原理:
1.通过实现InvocationHandler接口创建自己的代理处理器
2.通过反射机制得到目标类的所有构造方法和接口,并返回代理实例
3.代理对象对目标类的方法进行增强(即添加方法执行前的逻辑和方法执行后的逻辑并返回目标类)
特点:JDK动态代理是面向接口的代理模式,基于JDK的环境,无需导入jar包,如果目标对象没有实现接口,则不能使用JDK代理
JDK代理代码实现:
1.目标类接口:
public interface Targe {
public void sayHallo();
}
2.目标类接口实现:
public class TargeImpl implements Targe{
public void sayHallo() {
System.out.println("我是明星我很大牌");
}
}
3.JDK代理实现:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxyExample implements InvocationHandler{
private Object targe = null;
public Object bind(Object targe){
this.targe = targe;
//返回一个代理实例
return Proxy.newProxyInstance(targe.getClass().getClassLoader(), targe.getClass().getInterfaces(),this);
//方法参数:对象的所有构造方法,对象的所有接口,对象本身
}
public Object invoke(Object proxy,Method method,Object[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
System.out.println("我进入了事务所");
System.out.println("执行某些逻辑");
Object obj = method.invoke(targe, args);
System.out.println("在真实调用了目标类方法之后的逻辑");
return obj;
}
}
4.测试类:
import org.junit.Test;
public class ProxyText {
@Test
public void JdkProxyText(){
JDKProxyExample example = new JDKProxyExample();
Targe proxyTarge = (Targe) example.bind(new TargeImpl());
proxyTarge.sayHallo();
}
}
5.输出结果:
二、基于CGlib的代理增强实现:
实现原理:
1.首先加载代理对象的Class文件,通过修改其字节码,将代理对象设置成目标类的子类
2.设置代理对象继承目标类的构造方法(可以不做这一步),返回代理实例
3.代理对象对目标类的方法进行增强(即添加方法执行前的逻辑和方法执行后的逻辑并返回目标类)
特点:需要导入CGlib库,和对XML文件配置通过字节码底层继承目标类生成代理类,故如果目标类用final修是则会失败,与jdk相比能够代理没有实现接口的类。
CGlib代理增强的代码实现:
1.目标类:
public class TargeImpl implements Targe{
public void sayHallo() {
System.out.println("我是明星我很大牌");
}
}
2.CGlib的代理实现
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CGlibProxyExample implements MethodInterceptor {
public Object getProxy(Class cls){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(cls);//设置代理目标
enhancer.setCallback(this);//回调
enhancer.setClassLoader(cls.getClassLoader());
return enhancer.create();//返回一个代理类(new intercept)
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("调用目标方法前");
Object result = proxy.invokeSuper(obj, args);
System.out.println("真是调用方法后的逻辑");
return result;
}
}
3.xml文件配置
<!-- true 表示底层使用cglib代理,false表示底层使用JDK代理,默认为false-->
<aop:config proxy-target-class="true"></aop:config>
4.测试类:
public class ProxyText {
@Test
public void JdkProxyText(){
//基于JDK代理测试
/*JDKProxyExample example = new JDKProxyExample();
Targe proxyTarge = (Targe) example.bind(new TargeImpl());
proxyTarge.sayHallo();*/
//基于CGLib代码测试
TargeImpl proxy = (TargeImpl) new CGlibProxyExample().getProxy(TargeImpl.class);
proxy.sayHallo();
}
}
5.结果
三、jdk与CGlib代理增强的比较
JDK代理是面向接口的,如果目标类没有实现接口无法代理,是Spring的默认代理方式,创建代理速度快,而CGlib是字节码底层继承目标类来实现的,如果目标类被final修饰则会失败,但目标类不需要实现接口,需要导入CGlib.jar包,创建代理速度比jdk慢,但运行速度快
四、使用注意:
如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spirng默认采用JDK动态代理实现机制)
如果要被代理的对象不是个实现类那么,Spring会强制使用CGLib来实现动态代理。