JDKProxy与CGlibProxy
Spring 使用动态代理技术实现AOP. spring AOP使用两种代理机制
1.基于JDK代理
JDK动态代理主要涉及两个类:Proxy和InvocationHandler,自定义实现InvocationHandler定义横切逻辑,并通过反射机制调用目标类代码,将横切逻辑和业务代码编织一起。
Proxy通过InvocationHanbler动态创建某一接口实例,生成目标类代理对象。
用一个接口模拟
/** * ee * * @author MM * @create 2018-03-28 17:16 **/ public interface UserManage { void queryUser(String id); void addUser(String id, String name); }
public class UserManagerImpl implements UserManage { @Override public void addUser(String id, String name) { System.out.println("新增用户:" + name); } @Override public void queryUser(String id) { System.out.println("查询用户:" + id); } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * eee * * @author MM * @create 2018-03-28 17:18 **/ public class JDKProxyHandler implements InvocationHandler { //需要代理的目标对象 private Object targetObject; public JDKProxyHandler(Object targetObject) { this.targetObject = targetObject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //这里可以处理业务逻辑 doService(); return method.invoke(targetObject, args); } private void doService() { System.out.println("业务逻辑处理。。。"); } }
测试代码
public static void main(String[] args) { UserManage targetObject = new UserManagerImpl(); JDKProxyHandler handler = new JDKProxyHandler(targetObject); //创建代理对象第二个参数即表明了JDK动态代理只能对实现了接口的类生成代理,而不能针对类,如果直接用类会抛异常 UserManage userManagerJDK = (UserManage)Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), handler); userManagerJDK.addUser("tom", "test"); }
2.基于CGLib代理
针对JDK动态代理只能对接口创建代理实例,CGLIb来弥补这一缺陷。CGLIb代理使用底层字节码技术,可以为类创建一个子类,在子类中采用方法拦截,去拦截父类方法的调用并织如横切逻辑。
/** * sgg * * @author MM * @create 2018-03-28 17:22 **/ public class CGLibProxy implements MethodInterceptor { // CGLib需要代理的目标对象 private Object targetObject; public Object getProxy(Object obj){ this.targetObject = obj; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(obj.getClass()); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { doService(); return method.invoke(targetObject, args); } private void doService() { System.out.println("业务逻辑处理。。。"); } }
public static void main(String[] args) { UserManage userManager = (UserManage) new CGLibProxy() .getProxy(new UserManagerImpl()); userManager.addUser("tom", "test"); }
附上网上的总结:
spring对aop的支持
*如果目标对象实现了接口,默认情况下会采用jdk的动态代理实现aop
* 如果目标对象实现了接口,可以强制使用cglib实现aop
*如果目标对象没有实现了接口,必须采用cglib库,spring会自动在jdk动态代理和cglib之间转换
如何强制使用cglib实现aop?
* 添加cglib库,spring_home/cglib/*.jar
* 在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
jdk动态代理和cglib字节码生成的区别?
* jdk动态代理只能对实现了接口的类生成代理,而不能针对类
* cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法
因为是继承,所以该类或方法最好不要声明成final