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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值