zoukankan      html  css  js  c++  java
  • JDK和Cglib实现动态代理实例及优缺点分析

    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动态代理效率较高。

  • 相关阅读:
    这可能是全网最轻量级、对MVVM支持最好、可定制性最高的开源WPF Chart控件了
    WPF源代码分析系列一:剖析WPF模板机制的内部实现(五)
    WPF源代码分析系列一:剖析WPF模板机制的内部实现(四)
    WPF源代码分析系列一:剖析WPF模板机制的内部实现(三)
    WPF源代码分析系列一:剖析WPF模板机制的内部实现(二)
    WPF源代码分析系列一:剖析WPF模板机制的内部实现(一)
    深入理解.NET/WPF内存泄漏
    Cocos2d-X3.0 刨根问底(九)----- 场景切换(TransitionScene)源码分析
    Cocos2d-X3.0 刨根问底(八)----- 场景(Scene)、层(Layer)相关源码分析
    Cocos2d-X3.0 刨根问底(七)----- 事件机制Event源码分析
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6468573.html
Copyright © 2011-2022 走看看