静态代理和动态代理

静态代理和动态代理

(1)什么是代理?

大道理上讲代理是一种软件设计模式,目的地希望能做到代码重用。具体上讲,代理这种设计模式是通过不直接访问被代理对象的方式,而访问
被代理对象的方法。这个就好比 商户---->明星经纪人(代理)---->明星这种模式。我们可以不通过直接与明星对话的情况下,而通过明星经纪人(代理)与其产生间接对话。

(2)什么情况下使用代理?

  1. 设计模式中有一个设计原则是开闭原则,是说对修改关闭对扩展开放,我们在工作中有时会接手很多前人的代码,里面代码逻辑让人摸不着头脑(sometimes the code is really like shit),这时就很难去下手修改代码,那么这时我们就可以通过代理对类进行增强。
    即在我们维护一个项目的时候,不知道之前人写的是什么代码,不知道怎么去修改,就可以使用代理模式,在原有模式的基础上,对类进行增强,这样就没有改变原来的代码,但是增强了功能

  2. 我们在使用RPC框架的时候,框架本身并不能提前知道各个业务方要调用哪些接口的哪些方法 。那么这个时候,就可用通过动态代理的方式来建立一个中间人给客户端使用,也方便框架进行搭建逻辑,某种程度上也是客户端代码和框架松耦合的一种表现。

  3. Spring的AOP机制就是采用动态代理的机制来实现切面编程。

(3)静态代理和动态代理

我们根据加载被代理类的时机不同,将代理分为静态代理和动态代理。如果我们在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制,在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制

1、静态代理

  1. 创建一个接口,接口里面写代理者和被代理者都要使用的方法
  2. 被代理的对象实现这个接口,重写接口中的方法
  3. 代理者也实现这个接口,通过在代理者类中将被代理者作为属性(或者直接将接口作为属性,但是创建代理者类时要传入被代理者,然后使用向下转型),同时重写接口中的方法,重写的方法中一定要在被代理者重写的基础上

Eg:

接口类:

interface Person {
     void speak();
 }

真实实体类:

class Actor implements Person {
     private String content;
     public Actor(String content) {
         this.content = content;
     }

@Override
     public void speak() {
         System.out.println(this.content);
     }
 }

代理类:

class Agent implements Person {
     private Actor actor;
     private String before;
     private String after;
     public Agent(Actor actor, String before, String after) {
         this.actor = actor;
         this.before = before;
         this.after = after;
     }
     @Override
     public void speak() {
         //before speak
         System.out.println("Before actor speak, Agent say: " + before);
         //real speak
         this.actor.speak();
         //after speak
         System.out.println("After actor speak, Agent say: " + after);
     }
 }

测试方法:

public class StaticProxy {
     public static void main(String[] args) {
         Actor actor = new Actor("I am a famous actor!");
         Agent agent = new Agent(actor, "Hello I am an agent.", "That's all!");
         agent.speak();
     }
 }

结果:

在这里插入图片描述

2、动态代理

(1)、定义一个接口A,接口中有被代理者要被代理的方法
(2)、定义一个类(作为被代理类),这个类实现接口
(3)、定义一个类(作为代理类),同时之前定义一个Object类型的属性,到时候将要代理的类的对象赋值给这个属性,就代表了代理关系
(4)、代理类要实现InvocationHandle接口,表示这是一个代理类,这样就不用实现接口A了,这是和静态代理不同的一点
(5)、代理类中要重写InvocationHandle接口的invoke()

		public interface InvocationHandler { 

			public Object invoke(Object proxy, Method method, Object[] args )throws Throwable;

		}

     分析invoke方法:
				Proxy:表示被代理的类,使用时就是传入代理类中的那个Object类型的
				method:调用被代理的类的方法
				args:该方法需要传入的参数

(6)、在invoke()中,使用Object obj=method.invoke(this.proxy,args);//这条语句是真正调用方法的地方
(7)、 在代理类中创建一个代理方法,返回的就是被修改过的被代理对象
传入的参数是:被代理对象实现的接口的.class,
被代理的对象

		public static Object agent(Class interfaceClazz, Object proxy) { 

				return Proxy.newProxyInstance(interfaceClazz.getClassLoader(), new Class[]{interfaceClazz}, new MyHandler(proxy)); 

		} 

分析一下

		java.lang.reflect包中的Proxy类的newProxyInstance方法:

		public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException

			参数分析:loader:被代理的类的类加载器

									Interfaces:被代理的类实现的所有接口,用class[]数组接收

									invocationHandler:就是我们创建的被代理类对象

使用这个方法是为了返回一个被修改过的类的实例,从而可以自由的调用该实例的方法

(8)、测试类

创建一个被代理对象实现的接口
接口=被代理类.agent(传入接口的.class文件,传入要代理的对象)
通过接口调用被代理类中的方法。
例子:

public class JdkProxy {
	public static void main(String[] args) {
		Agent agent=new Agent(new Star());
		Person person=(Person) agent.getInstance();
		person.run(5);
		person.eat(3);
	}

}
//定义一个接口
interface Person{
	public void run(int length);
	public void eat(int times);
}
//定义一个被代理类实现接口
class Star implements Person{
	@Override
	public void run(int length) {
		// TODO Auto-generated method stub
		System.out.println("明星一天跑"+length+"km");
	}

	@Override
	public void eat(int times) {
		// TODO Auto-generated method stub
		System.out.println("明星一天吃"+times+"餐");
		
	}
}
//定义一个代理类,实现InvocationHandler接口
class Agent implements InvocationHandler{
	Object target;
	public Agent() {}
	public Agent(Object target) {
		this.target=target;
	}

//重写这个接口的invoke方法,有什么逻辑判断就在这个方法中
	@Override
	public Object invoke(Object arg0, Method method, Object[] args) throws Throwable {
		
		Object ret=method.invoke(this.target,args);
		String methodName=method.getName();
		if(methodName.equals("run")) {
			System.out.println("经济人说:你不要每天跑这么点");
		}
		if(methodName.equals("eat")) {
			System.out.println("经济人说:你不要每天吃这么多");
		}
		return ret;
	}

	public Object getInstance() {
		return Proxy.newProxyInstance(this.target.getClass().getClassLoader(), this.target.getClass().getInterfaces(), this);
	}
	
}


 

3、cglib代理
(1)、定义一个类作为被代理类,但是这个类并没有实现任何接口,如果这个类中有final的方法,则不能被cglib代理的
(2)、定义另一个类作为代理类,类中有一个属性为Object类型,用于继承要代理的对象
(3)、这个类实现了MethodInterceptor接口,同时重写了intercept()

public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,

                           MethodProxy proxy) throws Throwable;

		参数分析:obj:cglib生成的代理对象

					method:表示要拦截的方法

					args:方法要传入的参数

					Proxy:表示要触发父类的方法对象

(4)、在代理类中创建另一个方法:Object getInstance(Object target)

		参数分析:传入一个object类型的对象,表代表可以接受任何类型的类作为被代理类

		方法体:
		public Object getInstance(Object target) {

			 this.targetObject = target;  //将要代理的对象传进来,赋值给targetObject属性

			Enhancer enhancer = new Enhancer();

			enhancer.setSuperclass(target.getClass()); 

			enhancer.setCallback(this);

			 //注意该处代理的创建过程

			 Object proxyObj = enhancer.create();

		 return proxyObj;// 返回代理对象
	 }

例子:

//被代理类

public class HelloService {



   public HelloService() {

       System.out.println("HelloService构造");

   }

`` 

   /**

    \* 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的

    */

   final public String sayOthers(String name) {

       System.out.println("HelloService:sayOthers>>"+name);

       return null;

   }

`` 

   public void sayHello() {

       System.out.println("HelloService:sayHello");

   }

}

`` 

//代理类

public class CglibProxy implements MethodInterceptor {

  private Object targetObject;

  // 这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理



public Object getInstance(Object target) {

    this.targetObject = target;

    Enhancer enhancer = new Enhancer();

    enhancer.setSuperclass(target.getClass());

    enhancer.setCallback(this);

    //注意该处代理的创建过程

    Object proxyObj = enhancer.create();

    return proxyObj;// 返回代理对象

  }



  @Override

  public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

    Object obj = null;

    System.out.println("doSomething---------start");

    obj = method.invoke(targetObject, args);

    System.out.println("doSomething---------end");

    return obj;
    
}



}



 public static void main(String[] args) {

CglibProxy cglib=new CglibProxy();

    HelloService helloservice=(HelloService)cglib.getInstance(new HelloService());

    hello.service.sayHello();

  }



 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值