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 (动态代理源码解析) 

  

  

 

  

原文地址:https://www.cnblogs.com/xiaofuzi123456/p/11311929.html