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();
-
-
}
-
}
实现方式有两种,一种是通过JDK自带的动态代理,另外一种则是使用Cglib实现。
1.使用JDk实现动态代理
例如在Service层,我们有两个业务逻辑类LoginServiceImpl和UserServiceImpl:
-
interface LoginService{
-
public boolean checkUser();
-
}
-
-
class LoginServiceImpl implements LoginService{
-
-
public boolean checkUser() {
-
System.out.println( "LoginServiceImpl checkUser");
-
return false;
-
}
-
}
-
-
interface UserService{
-
public String getUserName();
-
}
-
-
class UserServiceImpl implements UserService{
-
-
-
public String getUserName() {
-
System.out.println( "UserServiceImpl getUserName");
-
return null;
-
}
-
-
}
-
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{
-
-
public boolean checkUser() {
-
System.out.println( "LoginServiceImpl checkUser");
-
return false;
-
}
-
}
-
-
interface UserService{
-
public String getUserName();
-
}
-
-
class UserServiceImpl implements UserService{
-
-
-
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;
-
}
-
-
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{
-
-
public boolean checkUser() {
-
System.out.println( "LoginServiceImpl checkUser");
-
return false;
-
}
-
}
-
-
interface UserService{
-
public String getUserName();
-
}
-
-
class UserServiceImpl implements UserService{
-
-
-
public String getUserName() {
-
System.out.println( "UserServiceImpl getUserName");
-
return null;
-
}
-
-
}
-
-
class CglibProxy implements MethodInterceptor
-
{
-
private Log logger = LogFactory.getLog(CglibProxy.class);
-
-
-
-
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动态代理效率较高。