• 静态代理,动态代理和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%左右。

  • 相关阅读:
    dubbox编译安装本地maven仓库
    NameNode中几个关键的数据结构
    spark学习总结
    Spark性能优化指南——基础篇
    Spark性能优化指南——高级篇
    Kafka文件存储机制那些事
    Presto实现原理和美团的使用实践
    archlinux locale-gen 命令出错
    git无法连接bitbucket/github时,出现"Permission deied(publickey)"
    转:《JavaScript—之对象参数的引用传递》
  • 原文地址:https://www.cnblogs.com/kkzhilu/p/12859517.html
Copyright © 2020-2023  润新知