静态代理,动态代理和CGLIB代理模式

代理模式

一、概述

  代理是一种模式,提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求,同时代理模式便于扩展目标对象功能的特点也为多人所用。

二、图形描述

三、代码实现

静态代理,由于比较简单,所有把代码都合到一起了: 

// 需要被代理的接口
public interface BussinessInterface {
	void execute();
}

// 基础实现类
public class Bussiness implements BussinessInterface {

	@Override
	public void execute() {
		System.out.println("柯贤铭在做生意~~~");
	}
}

// 在基础实现类的基础之上,封装一层方法
public class BussinessProxy implements BussinessInterface {
	
	private BussinessInterface bussinessImpl;
	
	public BussinessProxy(BussinessInterface bussinessImpl) {
        this.bussinessImpl = bussinessImpl;
    }
	
	@Override
    public void execute() {
        System.out.println("前拦截...");
        bussinessImpl.execute();
        System.out.println("后拦截...");
    }
}

// 测试类,真正使用的时候,我们采用增强之后的实现类
public class TestAgent {

	public static void main(String[] args) {
		BussinessInterface bussinessInterface = new Bussiness();
		BussinessInterface newBuss = new BussinessProxy(bussinessInterface);
		newBuss.execute();
	}
}

效果截图:

静态总结:

优点:可以做到不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。

缺点:因为代理对象,需要实现与目标对象一样的接口,会导致代理类十分繁多,不易维护,同时一旦接口增加方法,则目标对象和代理类都需要维护。

 

动态代理模式,由于代码量较少,我也融合到一起:

// 定义接口
public interface UserService {
	void saveUser();
}

// 定义接口实现类及方法
public class UserServiceImpl implements UserService {
	@Override
    public void saveUser() {
        System.out.println("调用 saveUser() 方法");
    }
}

// 定义代理工具类
public class MyProxyUtil {
	public static UserService getProxyByJDK(UserService service) {
         // 参数:目标对象的类加载器,目标对象的接口,代理对象的执行处理器
		UserService userService = (UserService) Proxy.newProxyInstance(service.getClass().getClassLoader(),
				service.getClass().getInterfaces(),
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("记录日志-开始");
						Object obj = method.invoke(service, args);
						System.out.println("记录日志-结束");
						return obj;
					}
				});
		return userService;
	}
}


// 测试类
public class Test {

	public static void main(String[] args) {
		// 创建目标对象
		UserService userService = new UserServiceImpl();
		// 生成代理对象
		UserService proxy = MyProxyUtil.getProxyByJDK(userService);
		// 调用目标对象方法
		userService.saveUser();
		System.out.println("===================================");
		// 调用代理对象方法
		proxy.saveUser();
	}
}

测试截图:

动态代理的总结

优点:代理对象无需实现接口,免去了编写很多代理类的烦恼,同时接口增加方法也无需再维护目标对象和代理对象,只需在事件处理器中添加对方法的判断即可。

缺点:代理对象不需要实现接口,但是目标对象一定要实现接口,否则无法使用JDK动态代理。

 

CGLib 动态代理

CGLib 动态代理相对于 JDK 动态代理局限性就小了很多,目标对象不需要实现接口,底层是通过继承目标对象产生代理子对象

代码,只是工具类方法多了一个:

public static UserService getProxyByCglib(UserService service) {
		// 创建增强器
		Enhancer enhancer = new Enhancer();
		// 设置需要增强的类的对象
		enhancer.setSuperclass(UserServiceImpl.class);
		// 设置回调方法
		enhancer.setCallback(new MethodInterceptor() {
			@Override
			public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
				long begin = System.currentTimeMillis();
				System.out.println("记录程序开始");
				Object object = methodProxy.invokeSuper(o, args);
				long end = System.currentTimeMillis();
				System.out.println("记录程序结束");
				return object;
			}
		});
		UserService userService = (UserService) enhancer.create();
		return userService;
	}

测试代码:

public class TestCglib {
	public static void main(String[] args) {
		// 创建目标对象
		UserService userService = new UserServiceImpl();
		// 生成代理对象
		UserService proxy = MyProxyUtil.getProxyByCglib(userService);
		// 调用目标对象方法
		userService.saveUser();
		System.out.println("===================================");
		// 调用代理对象方法
		proxy.saveUser();
	}
}

测试结果:

总结:

Cglib代理: 针对类来实现代理,对指定目标 产生一个子类 通过方法拦截技术拦截所有父类方法的调用。 我们要使用cglib代理必须引入 cglib的jar包

 

三种代理模式进行总的分析概括:

代理模式:代理类和被代理类实现共同的接口(或继承),代理类中存有指向被代理类的索引,实际执行时通过调用代理类的方法、实际执行的是被代理类的方法。

而AOP,是通过动态代理实现的。

一、简单来说:

  JDK动态代理只能对实现了接口的类生成代理,而不能针对类

  CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)

二、Spring在选择用JDK还是CGLiB的依据:

   (1)当Bean实现接口时,Spring就会用JDK的动态代理

   (2)当Bean没有实现接口时,Spring使用CGlib是实现

   (3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)

三、CGlib比JDK快?

  (1)使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

  (2)在对JDK动态代理与CGlib动态代理的代码实验中看,1W次执行下,JDK7及8的动态代理性能比CGlib要好20%左右。

 

posted @ 2018-09-24 21:53  Super-Kerwin  阅读(115)  评论(0编辑  收藏  举报