Spring AOP使用的核心技术是动态代理,说到动态代理就不得不和设计模式中的代理模式联系起来,通过代理模式我们可以对目标类进行功能增强,在某个方法的执行前后增加一些操作,例如计算方法执行效率、打印日志等。
看下面的例子,我们有一个目标类Target,我们需要在目标类的test方法中增加日志打印功能,这时候我们就可以通过代理模式来实现:
package com.proxy.test; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; class Target { public void test(){ System.out.println("Target test"); } } class TargetProxy { private Target target; private Log logger = LogFactory.getLog(TargetProxy.class); public TargetProxy(Target target) { this.target = target; } public void test() { logger.info("*****方法执行前**********"); target.test(); logger.info("*****方法执行后**********"); } } public class ProxyTest{ public static void main(String[] args) { Target target = new Target(); TargetProxy proxy = new TargetProxy(target); proxy.test(); } }在上面的例子中我们通过代理类TargetProxy对目标类进行的功能增强,所谓的动态代理就是指在程序运行期间,在内存中动态的生成代理类的字节码并实例化代理对象。
实现方式有两种,一种是通过JDK自带的动态代理,另外一种则是使用Cglib实现。
1.使用JDk实现动态代理
例如在Service层,我们有两个业务逻辑类LoginServiceImpl和UserServiceImpl:
interface LoginService{ public boolean checkUser(); } class LoginServiceImpl implements LoginService{ @Override public boolean checkUser() { System.out.println("LoginServiceImpl checkUser"); return false; } } interface UserService{ public String getUserName(); } class UserServiceImpl implements UserService{ @Override public String getUserName() { System.out.println("UserServiceImpl getUserName"); return null; } }我们要对LoginServiceImpl和UserServiceImpl中的方法增加日志打印功能,可以通过Jdk动态代理实现,案例代码如下:
package com.proxy.test.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; interface LoginService{ public boolean checkUser(); } class LoginServiceImpl implements LoginService{ @Override public boolean checkUser() { System.out.println("LoginServiceImpl checkUser"); return false; } } interface UserService{ public String getUserName(); } class UserServiceImpl implements UserService{ @Override public String getUserName() { System.out.println("UserServiceImpl getUserName"); return null; } } class ProxyHandler implements InvocationHandler{ private Object target; private Log logger = LogFactory.getLog(ProxyHandler.class); public void setTarget(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] param) throws Throwable { logger.info("*********代理方法执行前************"); Object retObj = method.invoke(target, param); logger.info("*********代理方法执行后************"); return retObj; } } public class ProxyTestJDK { public static void main(String[] args) { //创建目标对象 LoginService loninService = new LoginServiceImpl(); UserService userService = new UserServiceImpl(); ProxyHandler proxyHandler = new ProxyHandler(); //创建LoginService代理对象 proxyHandler.setTarget(loninService); LoginService loninService$Proxy = (LoginService) Proxy.newProxyInstance(loninService.getClass().getClassLoader(), loninService.getClass().getInterfaces(), proxyHandler); loninService$Proxy.checkUser(); //创建UserService代理对象 proxyHandler.setTarget(userService); UserService userService$Proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), proxyHandler); userService$Proxy.getUserName(); } }运行程序输出:
十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept 信息: *********代理方法执行前************ LoginServiceImpl checkUser 十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept 信息: *********代理方法执行后************ 十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept 信息: *********代理方法执行前************ UserServiceImpl getUserName 十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept 信息: *********代理方法执行后************
2.使用Cglib动态代理实现
对于上面的需求我们也可以通过Cglib实现,具体代码如下:
package com.proxy.test.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; interface LoginService{ public boolean checkUser(); } class LoginServiceImpl implements LoginService{ @Override public boolean checkUser() { System.out.println("LoginServiceImpl checkUser"); return false; } } interface UserService{ public String getUserName(); } class UserServiceImpl implements UserService{ @Override public String getUserName() { System.out.println("UserServiceImpl getUserName"); return null; } } class CglibProxy implements MethodInterceptor { private Log logger = LogFactory.getLog(CglibProxy.class); @Override public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable { logger.info("*********代理方法执行前************"); Object retObj = methodProxy.invokeSuper(proxy, params); logger.info("*********代理方法执行后************"); return retObj; } //返回目标对象的代理对象 public Object newProxy(Object target) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); enhancer.setClassLoader(target.getClass().getClassLoader()); return enhancer.create(); } } public class ProxyTestCglib { public static void main(String[] args) { //创建目标对象 LoginService loninService = new LoginServiceImpl(); UserService userService = new UserServiceImpl(); CglibProxy proxy = new CglibProxy(); //创建代理对象 LoginService loninService$Proxy = (LoginService)proxy.newProxy(loninService); UserService userService$Proxy = (UserService)proxy.newProxy(userService); loninService$Proxy.checkUser(); userService$Proxy.getUserName(); } }
3.二者优缺点分析
使用JDK动态代理,目标类必须实现的某个接口,如果某个类没有实现接口则不能生成代理对象。
Cglib原理是针对目标类生成一个子类,覆盖其中的所有方法,所以目标类和方法不能声明为final类型。
从执行效率上看,Cglib动态代理效率较高。