架构学习之路(一)源码分析 5 代理模式

11 篇文章 0 订阅

架构学习之路(一)源码分析 4 原型模式

  1. 代理模式(Proxy)

    1. 结构型

    2. 目标对象

      1. 被代理人
        1. 这件事一定要做,但是没时间坐或者不想做
        2. 做最终决定方法
      2. 代理人
        1. 执行者
        2. 拿到被代理人的引用
        3. 能够调用被代理人的做最终决定的方法
        4. 只参与过程或者过程的某几个环节
    3. 为其他对象提供一种代理,以控制对这个对象的访问

    4. 结构上与 Decorator 类似,但 Proxy 是控制,更像是一种对功能的限制,而 Decorator 是增加职责

    5. Spring 的 Proxy 模式在 AOP 中有体现,比如 JdkDynamicAopProxy 与 Cglib2AopProxy

    6. 作用

      1. AOP 实现
      2. 拦截器
      3. 解耦
    7. 生活场景

      1. 房屋中介
      2. 售票黄牛
      3. 婚介所
      4. 经纪人
      5. 快递
      6. 事物代理
      7. 非嵌入式日志监听
    8. 模式

      1. 静态代理

        1. 在代理之前所有东西都是已知的
        2. 扩展性差
        3. 人工
        package source.patterns.proxy.staticed;
        
        /**
         * 代理人接口
         * 静态代理缺点:会有很多其他可代理的方法,但单一被代理人无法完成,如租房,购物...
         */
        public interface Person {
        	void findLove();
        }
        package source.patterns.proxy.staticed;
        
        /**
         * 被代理人
         */
        public class Son implements Person{
        	/**
        	 * 做决定的方法,但没有时间自己去做
        	 */
        	public void findLove(){
        		System.out.println("找对象:肤白貌美大长腿");
        	}
        }
        package source.patterns.proxy.staticed;
        
        /**
         * 代理人
         */
        public class Father {
        	private final Son son;
        	
        	/**
        	 * 静态代理:类是固定的,不能代理其他类
        	 */
        	public Father(Son son){
        		// 拿到被代理人的引用
        		this.son = son;
        	}
        	public void findLove(){
        		System.out.println("根据你得要求物色");
        		// 让被代理人做决定
        		son.findLove();
        		System.out.println("双方服务是否同意");
        	}
        }
        package source.patterns.proxy.staticed;
        
        /**
         * 代理人
         */
        public class Matchmaking {
        	private final Person person;
        	public Matchmaking(Person person){
        		this.person = person;
        	}
        	
        	public void findLove(){
        		System.out.println("婚介根据你的需求找对象");
        		person.findLove();
        		System.out.println("自己绝对合适不合适");
        	}
        }
        
      2. 动态代理

        1. 在代理之前所有东西都是未知的

        2. 扩展性强

        3. 自动化

        4. 实现形式

          1. JDK

            public interface Person {
            	void findLove();
            	void findWork();
            }
            
            /**
             * 代理人:可以随便扩展,找对应的代理人
             */
            public class Mark implements Person{
            	@Override
            	public void findLove(){
            		System.out.println("高富帅");
            	}
            	
            	@Override
            	public void findWork() {
            		System.out.println("找工作");
            	}
            }
            
            /**
             * 被代理人
             */
            public class Matchmaking implements InvocationHandler {
            	private Person person;
            	public Object getInstance(Person person){
            		this.person = person;
            		Class<?> clz = person.getClass();
            		//用来生成一个新的对象(字节码重组来实现)
            		return Proxy.newProxyInstance(clz.getClassLoader(),clz.getInterfaces(),this);
            	}
            	
            	@Override
            	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            		System.out.println("婚介开始帮忙找对象");
            		method.invoke(this.person,args);
            		System.out.println("合适的话结账,不合适的话继续");
            		return null;
            	}
            }
            
            public class JobIntroduction implements InvocationHandler {
            	private Person person;
            	public Object getInstance(Person person){
            		this.person = person;
            		Class<?> clz = person.getClass();
            		return Proxy.newProxyInstance(clz.getClassLoader(), clz.getInterfaces(), this);
            	}
            	
            	@Override
            	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            		System.out.println("开始找工作");
            		method.invoke(this.person, args);
            		System.out.println("工作找完了");
            		return null;
            	}
            }
            
          2. CGLIB

            1. 原理:字节码重组
              1. 通过反射拿到被代理对象的引用,并且获取到它所有的接口
              2. 通过 JDK Proxy 类重新生成一个新的类
              3. 动态的生成一些 Java 代码,把新加的业务逻辑用一定的逻辑用代码去调用
              4. 编译新生成的 Java 代码
              5. 再重新加载到 jvm 中运行
            2. JDK 规范:$符号开头的一般都是自动生成的,如内部类
            3. 通过反编译工具可以查看源代码
            /**
             * 被代理人
             */
            public class Tom {
            	public void findLove(){
            		System.out.println("只为结婚");
            	}
            }
            
            /**
             * 代理人:需要 cglib.jar
             * cglib.jar 依赖于 asm.jar
             * cglib-3.3.0 会发出非法反射的警告
             */
            public class Matchmaking implements MethodInterceptor {
            	public Object getInstance(Class<?> clz){
            		Enhancer enhancer = new Enhancer();
                    // 要把哪个类设置为即将生成的新类的父类
            		 enhancer.setSuperclass(clz);
            		 enhancer.setCallback(this);
            		 return enhancer.create();
            	}
            	
            	@Override
            	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            		//业务的增强
            		System.out.println("开始找对象");
            		methodProxy.invokeSuper(o,objects);
            		System.out.println("找完了");
            		return o;
            	}
            }
            
          3. 自己写动态代理

            public interface MyInvocationHandler {
            	Object invoke(Object object, Method method,Object[] objects) throws InvocationTargetException, IllegalAccessException;
            }
            
            /**
             * 编译生成的.class 文件加载到 JVM 中
             */
            public class MyClassLoader extends ClassLoader{
            	private final File classPathFile;
            	public MyClassLoader(){
            		final String path = MyClassLoader.class.getResource("").getPath();
            		this.classPathFile = new File(path);
            	}
            	
            	@Override
            	protected Class<?> findClass(String name) throws ClassNotFoundException {
            		String className = MyClassLoader.class.getPackage().getName()+"."+name;
            		if(classPathFile!=null){
            			final File file = new File(classPathFile,name.replaceAll("\\.","/")+".class");
            			if(file.exists()){
            				FileInputStream fileInputStream = null;
            				ByteArrayOutputStream byteArrayOutputStream = null;
            				try {
            					fileInputStream = new FileInputStream(file);
            					byteArrayOutputStream = new ByteArrayOutputStream();
            					byte[] bytes = new byte[1024];
            					int len;
            					while((len = fileInputStream.read(bytes))!=-1)
            						byteArrayOutputStream.write(bytes,0,len);
            					return defineClass(className, byteArrayOutputStream.toByteArray(), 0, byteArrayOutputStream.size());
            				} catch (IOException e) {
            					e.printStackTrace();
            				}finally {
            						try {
            							if(fileInputStream!=null) fileInputStream.close();
            							if(byteArrayOutputStream!=null) byteArrayOutputStream.close();
            						} catch (IOException e) {
            							e.printStackTrace();
            						}
            				}
            			}
            		}
            		return null;
            	}
            }
            
            public class MyProxy {
            	public static final String ln = "\r\n";
            	public static int num = 0;
            	public static Object newProxyInstance(MyClassLoader classLoader,Class<?>[] interfaces,MyInvocationHandler invocationHandler){
            		// 1.动态生成源代码.java 文件
            		final String src = generateSrc(interfaces);
            		// 2.把.java 文件输出到磁盘
            		final String path = MyProxy.class.getResource("").getPath();
            		final File file = new File(path,"$MyProxy"+num+".java");
            		FileWriter fileWriter = null;
            		try {
            			fileWriter = new FileWriter(file);
            			fileWriter.write(src);
            			fileWriter.flush();
            		} catch (IOException e) {
            			e.printStackTrace();
            		}finally {
            			if(fileWriter!=null) {
            				try {
            					fileWriter.close();
            				} catch (IOException e) {
            					e.printStackTrace();
            				}
            			}
            		}
            		// 3.把生成的.java 文件编译成.class 文件
            		final JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
            		final StandardJavaFileManager standardFileManager = systemJavaCompiler.getStandardFileManager(null, null, null);
            		final Iterable<? extends JavaFileObject> javaFileObjects = standardFileManager.getJavaFileObjects(file);
            		final JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, standardFileManager, null, null, null, javaFileObjects);
            		task.call();
            		try {
            			standardFileManager.close();
            		} catch (IOException e) {
            			e.printStackTrace();
            		}
            		// 4.编译生成的.class 文件加载到 JVM 中
            		try {
            			final Class<?> $MyProxy0 = classLoader.findClass("$MyProxy"+num);
            			final Constructor<?> constructor = $MyProxy0.getConstructor(MyInvocationHandler.class);
            			// 5.返回字节码重组以后的新的代理对象
            			file.delete();
            			num++;
            			return constructor.newInstance(invocationHandler);
            		} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            			e.printStackTrace();
            		}
            		return null;
            	}
            	
            	private static String generateSrc(Class<?>[] interfaces){
            		final StringBuffer stringBuffer = new StringBuffer();
            		stringBuffer.append("package source.patterns.proxy.dynamic.custom;").append(ln);
            		final Type[] genericInterfaces = interfaces[0].getGenericInterfaces();
            		if(genericInterfaces.length!=0){
            			for(Type type:genericInterfaces){
            				stringBuffer.append("import ").append(type.getTypeName()).append(";").append(ln);
            			}
            		}
            		stringBuffer.append("import java.lang.reflect.Method;").append(ln);
            		stringBuffer.append("public class $MyProxy").append(num).append(" implements ").append(interfaces[0].getName()).append("{").append(ln);
            		stringBuffer.append("MyInvocationHandler h;").append(ln);
            		stringBuffer.append("public $MyProxy").append(num).append("(MyInvocationHandler h){").append(ln);
            		stringBuffer.append("this.h = h;").append(ln);
            		stringBuffer.append("}").append(ln);
            		int i = 0;
            		for(Method method:interfaces[0].getMethods()){
            			stringBuffer.append("public ").append(method.getReturnType().getName()).append(" ").append(method.getName()).append("(){").append(ln);
            			stringBuffer.append("try{").append(ln);
            			stringBuffer.append("Method method").append(i).append(" = ").append(interfaces[0].getName()).append(".class.getMethod(\"").append(method.getName()).append(
            					"\",new Class[]{});").append(ln);
            			stringBuffer.append("this.h.invoke(this,method").append(i).append(",null);").append(ln);
            			stringBuffer.append("}catch(Exception e){").append(ln);
            			stringBuffer.append("e.printStackTrace();").append(ln);
            			stringBuffer.append("}");
            			i++;
            		}
            		stringBuffer.append("}").append(ln);
            		stringBuffer.append("}");
            		return String.valueOf(stringBuffer);
            	}
            }
            
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值