动态代理分为两种:JDK动态代理与CGLIB动态代理.
什么是代理(proxy)?什么是动态代理?
代理: 代理拥有被代理的属性与方法,可以代表被代理类完成被代理类不想做,不得不做,或者想做却不能做的任务。比如说,一个方法无法通过自身来调用,可以通过代理来调用。
动态代理:代理者是全能的,能够代理任何的对象,所以在代理前都不清楚要代理什么内容,只有在创建号代理之后才能明确。
一、通过JDK实现切面逻辑的动态代理
接口代码
package JDKproxy;
public interface Userinterface {
void addUser();
}
接口实现类:
package JDKproxy;
public class UserinterfaceImpl implements Userinterface {
public void addUser() {
System.out.println("添加用户");
}
}
前置切入的方法与后置切入的方法
public static void check(){
System.out.println("检查用户属性");
}
public static void save(){
System.out.println("用户属性归档");
}
动态代理的实现类
package JDKproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//JDK提供的调用方法的一个接口,代理机制下调用方法的接口,必须实现invoke()方法
public class JDKProxy implements InvocationHandler {
//被代理的对象
public Object targetobj;
//创建被代理对象
public Object createProxy(Object targetobj ){
this.targetobj=targetobj;
//创建一个代理对象的方法,第一个参数获得类加载器,帮助动态或者静态加载类,每一个类都有一个类加载器,第二个参数获得对象所在的类所实现的任何一个接口。
//第三个参数是是invocationhandle接口本身
return Proxy.newProxyInstance(targetobj.getClass().getClassLoader(),targetobj.getClass().getInterfaces(),this);
}
//传入一个被代理对象,返回一个代理的对象
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//真正调用方法的地方
//切入前,前置切入
Aspect.check();
Object ret= method.invoke(targetobj,args);
//切入后,后置切入
Aspect.save();
return ret;
}
}
主方法:
package JDKproxy;
public class RunTest {
public static void main(String[] args) {
Userinterface userinterface=new UserinterfaceImpl();
// userinterface.addUser();
//创建userinterface的动态代理
Userinterface proxy=(Userinterface) new JDKProxy().createProxy(userinterface);
//通过动态代理调用被代理对象的方法
proxy.addUser();
}
}
首先,通过createProxy()的newInstance方法创建被代理对象的动态代理对象,在创建好代理对象之后,代理对象调用方法时,会自动调用invoke()方法,在invoke方法里实现拓展方法。并通过method反射机制实现之前的方法。
二、CGLIB实现动态代理
CGLIb是通过字节码技术,在运行时动态创建被代理者的子类。
第一步 添加cglib依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>
第二步 创建CGLIB代理实现类
package CGLIBProxy;
import JDKproxy.Aspect;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGlibproxy implements MethodInterceptor {
//在字节码阶段,调用代码的时候会调用的方法
public Object createProxy(Object targetobj){
//通过Enhance类来创建CGlib的动态代理对象
Enhancer enhancer=new Enhancer();
//设置它的类为被代理对象所在的类
enhancer.setSuperclass(targetobj.getClass());
//回调
enhancer.setCallback(this);
//创建代理对象
return enhancer.create();
}
public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Aspect.check();
//切面逻辑在这里触发,调用父类的方法
methodProxy.invokeSuper(proxy,objects);
Aspect.save();
return null;
}
}
实现MethodInterceptor接口,使用createproxy方法创建产生代理对象,在代理对象调用被代理对象的方法时会自动调用intercept方法,此方法也就是切面逻辑出发的地方。
package CGLIBProxy;
public class Runtest {
public static void main(String[] args) {
User user=new User();
user.addUser();
//createProxy的参数时被代理的对象,此方法用于产生代理
User Proxy=(User) new CGlibproxy().createProxy(user);
Proxy.addUser();
}
}
三、二者区别
1、JDK动态代理是在代码创建阶段生成的,优点:创建对象很快,但整体运行逻辑会很慢。
2、CGLIB在代理运行阶段创捷一个子类继承被代理类。