zoukankan      html  css  js  c++  java
  • Java代理模式

    一.静态代理

       代理类在代码运行前存在,这种代理的方式称为静态代理,这种方式的代理类是通我们自己编写来实现,一般情况下,静态代理模式的代理类和委托类实现同一个接口。

    简单地代码实现如下:Lets GO

      

    /**
     * @Author zhangfu
     * @Date 23:17 2019/8/5
    * 接口 */ public interface UserManager { public void addUser(String userId, String userName); public void delUser(String userId); public String findUser(String userId); public void modifyUser(String userId, String userName); }

      

    /**
     * @Author: 13394
     * @CreateDate: 2019/8/5 23:22
     * 真实对象
     */
    public class UserManagerImpl implements UserManager {
        @Override
        public void addUser(String userId, String userName) {
            System.out.println("添加用户!!!!!!!");
        }
    
        @Override
        public void delUser(String userId) {
            System.out.println("删除用户!!!!!!!");
        }
    
        @Override
        public String findUser(String userId) {
            System.out.println("查询用户!!!!!!!");
            return null;
        }
    
        @Override
        public void modifyUser(String userId, String userName) {
            System.out.println("修改用户!!!!!!!");
        }
    }
    

     

    /**
     * @Author: 13394
     * @CreateDate: 2019/8/5 23:25
    * 代理类 */ public class ProxyUserManagerImpl implements UserManager { private UserManager userManager; public ProxyUserManagerImpl(UserManager userManager) { this.userManager = userManager; } @Override public void addUser(String userId, String userName) { System.out.println("添加用户开始!!!!!!!!!!!!!!!"); userManager.addUser(userId,userName); System.out.println("添加用户结束!!!!!!!!!!!!!!!!!"); } @Override public void delUser(String userId) { } @Override public String findUser(String userId) { return null; } @Override public void modifyUser(String userId, String userName) { } }

     

    /**
     * @Author: 13394
    * 测试类 */ public class ClientTest { public static void main(String[] args) { UserManager userManager=new ProxyUserManagerImpl(new UserManagerImpl()); userManager.addUser("1","张三"); } }

    二.动态代理,JDK内置的Proxy实现  

      什么是动态代理:

    代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

    在使用动态代理时,我们需要定义一个位于代理类与委托类之间的中介类,这个中介类被要求实现InvocationHandler接口

    public interface Subject {
    	
    	void hello(String str);
    	String bye();
    }
    
    //委托类
    public class RealSubject implements Subject{ @Override public void hello(String str) { System.out.println("Hello " + str); } @Override public String bye() { System.out.println("Goodbye"); return "Over"; } }
    //中介类
    public class InvocationHandlerDemo implements InvocationHandler { // 这个就是我们要代理的真实对象 private Object subject; // 构造方法,给我们要代理的真实对象赋初值 public InvocationHandlerDemo(Object subject) { this.subject = subject; } /* * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数 * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象 * 第二个参数realSubject.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了 * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上 */ public Object createProxyIntance(){ return Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在代理真实对象前我们可以添加一些自己的操作 System.out.println("Before method"); System.out.println("Call Method: " + method); // 当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用 Object obj = method.invoke(subject, args); // 在代理真实对象后我们也可以添加一些自己的操作 System.out.println("After method"); return obj; } }
    public class ClientTest {
       public static void main(String[] args) {
    	   // 我们要代理的真实对象
           Subject realSubject = new RealSubject();
           //我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
           InvocationHandlerDemo handler = new InvocationHandlerDemo(realSubject); 
           Subject subject=(Subject)handler.createProxyIntance();
           String result = subject.bye();
           System.out.println("Result is: " + result);
           System.out.println("代理的类型:"+subject.getClass().getName());
       
    }
    }
    

     中介类持有一个委托类对象引用,在invoke方法中调用了委托类对象的相应方法,通过聚合方式持有委托类对象引用,把外部对invoke的调用最终都转为对委托类对象的调用。这不就是我们上面介绍的静态代理的一种实现方式吗?实际上,中介类与委托类构成了静态代理关系,在这个关系中,中介类是代理类,委托类就是委托类; 代理类与中介类也构成一个静态代理关系,在这个关系中,中介类是委托类,代理类是代理类。也就是说,动态代理关系由两组静态代理关系组成,这就是动态代理的原理

    三.动态代理,cjlib 代理

        cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。而java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

    <dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib-nodep</artifactId>
    <version>3.1</version>
    </dependency>

    委托类是java动态代理的代码。上面

    /**
     * cjlib 动态代理
     * @author 86133
     *
     */
    public class CjlibDynamicProxy implements MethodInterceptor {
    	
    	Object targetObject;  //目标对象
    	/**
    	 * 动态生成一个新的类,使用父类的无参构造方法创建一个指定了特定回调的代理实例
    	 * @param obj
    	 * @return
    	 */
    	public Object getProxyObject(Object obj){
    		this.targetObject=obj;
    		 //增强器,动态代码生成器
    		Enhancer enhancer=new Enhancer();
    		 //回调方法
    		enhancer.setCallback(this);
    		//设置生成类的父类类型
    		enhancer.setSuperclass(targetObject.getClass());
    		//动态生成字节码并返回代理对象
    		return enhancer.create();
    	}
    
    	@Override
    	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    		Object result = proxy.invoke(targetObject,args);
    		return result;
    	}
    
    }
    

      

    public class ClientTest {
       public static void main(String[] args) {
    	
           CjlibDynamicProxy cjlibDynamicProxy=new CjlibDynamicProxy();
           Subject subjects=(Subject) cjlibDynamicProxy.getProxyObject(realSubject);
           String result1 = subjects.bye();
           System.out.println("结果:"+result+"代理类型:"+subjects.getClass().getName());
    }
    }
    

     四. SpringAop 的两种代理方式(Jdk的动态代理和Cjlib的动态代理)        

          JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。 CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类或方法最好不要声明成final 
           

       如果spring会使用JDK的java.lang.reflect.Proxy类,它允许Spring动态生成一个新类来实现必要的接口,织入通知,并且把对这些接口的任何调用都转发到目标类。

     如果spring使用CGLIB库生成目标类的一个子类,在创建这个子类的时候,spring织入通知,并且把对这个子类的调用委托到目标类。

    参考博客:https://www.cnblogs.com/hadoop-dev/p/7095464.html

                      https://www.cnblogs.com/best/p/5679656.html#_label3

                      https://www.cnblogs.com/yulinfeng/p/7811965.html (动态代理源码解析) 

      

      

     

      

  • 相关阅读:
    第三次冲刺
    第二次冲刺
    第一次冲刺
    团队学习
    git and github
    还不够格的程序员
    CF1602F. Difficult Mountain
    线性基
    欧拉回路学习笔记
    莫比乌斯反演-学习笔记
  • 原文地址:https://www.cnblogs.com/xiaofuzi123456/p/11311929.html
Copyright © 2011-2022 走看看