• 02.代理模式
  • 发布于 2个月前
  • 44 热度
    0 评论

代理解释:

被代理人因为某些原因或者不方便的去做一些事情的时候可以找到对应的代理人来帮他做。只需要告诉代理人关于被代理人要遇到的事情是什么即可。不管怎样,代理人都是在帮被代理人做事情,这是最本质的核心。

代理解释:


    静态代理和动态代理。
    而动态代理又分为JDK动态代理和CGLIB动态代理。
    Spring中AOP的源码之中用了两种动态代理来实现拦截切入功能。

1.静态代理:

- (1)需要代理对象和被代理对象实现相同的接口
- (2)优点:不需要修改对象就可以扩展被代理对象的功能
- (3)缺点:冗余和不易维护。代理类过多。当接口增加方法的时候目标对象与代理对象都要进行修改。

贴代码:

package com.chen.proxy;

//官司接口  用于当事人与律师共同来实现
public interface LawSuit {
	void lawSuitSign(); //进行诉权
}


package com.chen.proxy;

//律师要先帮别人打官司肯定要实现这个接口
public class Lawyer implements LawSuit {
	/**
	 * 律师作为这类想打官司但是却没有相应的法律知识的人的代理
	 */
	private LawSuit lawSuit;
	
	//默认情况下这个打官司的人是你自己一个人
	public Lawyer() {
		this.lawSuit = new YourSelf();
	}
	
	//但是为了复用还可以是任何人,只要是想打官司。
	public Lawyer(LawSuit lawSuit) {
		this.lawSuit = lawSuit;
	}
	
	//诉权
	@Override
	public void lawSuitSign() {
		System.out.println("你不爽,可以,我是律师我来帮你打官司,我是你的代理人");
		System.out.println("我可以帮你做任何事情!");
		this.lawSuit.lawSuitSign();
	}
}

package com.chen.proxy;

//你自己要先打官司你也要实现这个接口
public class YourSelf implements LawSuit {
	
	//诉权
	@Override
	public void lawSuitSign() {
		System.out.println("我很不爽,我想要打官司!");
	}

}

package com.chen.proxy;

public class Run {
	public static void main(String[] args) {
		//对面人把我打了我需要打官司
		
		//1.我先把我的代理人律师叫出来
		Lawyer lawyer = new Lawyer();
		//对面人开始和我的律师进行沟通辨达。
		//无论怎么样沟通和争辩,最后只做一件事儿,帮我打赢官司
		lawyer.lawSuitSign();
		//表面上律师在打官司实际上是为我而打。
		
		//当然这个律师还可以为其他人打官司,只要你和律师有一个共同的目的
		//也就是实现LawSuit即可
		/**
		 你不爽,可以,我是律师我来帮你打官司,我是你的代理人
		我可以帮你做任何事情!
		我很不爽,我想要打官司!
		 */
		//总结:代理模式主要是java的多态,做事儿的是代理类也就是我的律师帮我打官司,
		//而我就是因为有了纠纷。你想和我打官司不好意思先和我的律师去打。
		//我的律师能帮我打官司吗,当然能,同根共同都是为了官司这个接口。
	}
}


2. JDK动态代理:

- (1)定义:利用反射动态的在内存中生成代理对象。重点:动态生成对象。
- (2)静态代理和动态代理的区别:
- ①静态代理编译期间确定,编译完成后代理类是一个class文件。
- ②动态代理是代码运行时才生成的,所以编译期间并没有实际的class文件,而是在运行时动态的生成类字节码,然后才会加载到JVM中进行使用。
- (3)特点:我,也就是目标对象,也就是被代理类必须实现打官司这个接口才可以实现动态代理技术,否则不可以。不多说,还是上代码。
贴代码:
package com.chen.jdk.proxy;

//接口打官司
public interface LawSuit {
	void lawSuitSign();//进行诉权
}


package com.chen.jdk.proxy;

//被代理类也就是目标对象。
public class YourSelf implements LawSuit {
	
	@Override
	public void lawSuitSign() {
		System.out.println("我自己要打官司,所以我实现了接口!");
	}

}


package com.chen.jdk.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//动态代理对象也就是代理对象
public class Lawyer  {
	//维护一个目标对象
	private Object yourSelf;

	public Lawyer(Object yourSelf) {
		this.yourSelf = yourSelf;
	}
	
	//为目标对象也就是我自己去生成一个代理对象律师。
	public Object getProxyLawyer() {
		// classLoader  指定目标类所使用的类加载器
		// Class<?>[] arg1,  指定目标类实现的的接口类型的集合数组
		//invocationHandler  事件处理器
		return Proxy.newProxyInstance(yourSelf.getClass().getClassLoader() , yourSelf.getClass().getInterfaces(), new InvocationHandler() {
			//最最最重要的一个,用于做真正事情的进行方法调用和返回结果
			@Override
			public Object invoke(Object proxy, Method method, Object[] arg1) throws Throwable {
				System.out.println("代理做事儿之前应该有一些逻辑代码的!");
				Object returnValue = method.invoke(yourSelf, arg1);
				System.out.println("代理做完事儿也应该有一些逻辑处理的!");
				return returnValue;
			}
		});
	}
}

package com.chen.jdk.proxy;

public class Run {
	public static void main(String[] args) {
		//我自己实现了打官司这个接口
		LawSuit self = new YourSelf();
		//创建一个代理对象律师来
		LawSuit proxyLawyer = (LawSuit) new Lawyer(self).getProxyLawyer();
		//律师帮我打官司
		proxyLawyer.lawSuitSign();
		/**
		代理做事儿之前应该有一些逻辑代码的!
		我自己要打官司,所以我实现了接口!
		代理做完事儿也应该有一些逻辑处理的!
		 */
	}
}


JDK动态代理和静态代理的区别是:

       静态代理的代理类和目标类都要实现共同的接口,而JDK动态代理的代理类并不需要实现,利用JDK的反射的特性,利用事件处理类种的invoke方法去实现AOP的拦截功能,这就是Spring种赖以生存的AOP基本原理之一。要求就是所有目标类去实现同一接口。也就是所有要打官司的人必须都要去实现这个官司接口。


3.CGLIB动态代理技术:

- (1)特点:可以去代理没有实现接口的类,因为JDK动态代理要求被代理对象必须实现一个或多个接口。
- (2)CGLIB底层通过一个字节码框架ASM来转换字节码并生成新的类。放个链接:关于ASM的https://blog.csdn.net/aesop_wubo/article/details/48930913 
- (3)被代理对象不可以被final修饰!因为CGLIB会去继承目标对象,需要重写方法,所以目标对象不可以被final修饰。
贴代码:
package com.chen.cglib.proxy;

//被代理对象,此时任何接口都未实现。
//最最重要的是不可以被final修饰。
public class YourSelf {
	public void lawSuitSign() {
		System.out.println("我想打官司,但是我没有实现任何接口。");
	}
}


package com.chen.cglib.proxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

//代理类也就是律师类就不能够不去实现东西了。
//所以代理类要实现一个叫做Method的抽象方法。
//public abstract java.lang.Object intercept(java.lang.Object arg0, java.lang.reflect.Method arg1, java.lang.Object[] arg2, org.springframework.cglib.proxy.MethodProxy arg3) 
public class Lawyer implements MethodInterceptor{
	//在内部维护一个对象,也就是想要打官司的你
	private Object yourSelf;
	
	public Lawyer(Object yourSelf) {
		this.yourSelf = yourSelf;
	}
	
	//为目标对象生成代理对象律师  增强一下
	//这就是动态生成一个子类对象从而实现对目标的扩展
	public Object getProxyLawyer() {
		//工具类
		Enhancer enhancer = new Enhancer();
		//设置父类,也就是被代理类。
		enhancer.setSuperclass(yourSelf.getClass());
		//设置回调的函数 回调函数的参数必须是代理对象 		增强目标类调用
		//的是代理类对象的intercept方法。
		enhancer.setCallback(this);
		//创建子类对象的代理
		return enhancer.create();
	}
	
	//用于增强目标类 实际上真正要做的内容在这里
	@Override
	public Object intercept(Object obj, Method method, Object[] objs, MethodProxy proxy) throws Throwable {
		System.out.println("开始之前你肯定要做点什么事情!");
		proxy.invokeSuper(obj, objs);
		System.out.println("结束之后你也要插入一点逻辑呢!");
		return null;
	}
	
}


package com.chen.cglib.proxy;

public class Run {
	public static void main(String[] args) {
		//被代理类也就是想打官司的你
		YourSelf self = new YourSelf();
		//代理对象也就是帮你打官司的人律师
		YourSelf proxy = (YourSelf) new Lawyer(self).getProxyLawyer();
		//去打官司
		proxy.lawSuitSign();
		/**
		开始之前你肯定要做点什么事情!
		我想打官司,但是我没有实现任何接口。
		结束之后你也要插入一点逻辑呢!
		 */
	}
}

总结:关于静态代理,JDK动态代理,CGLIB动态代理以及Spring框架中AOP的具体实现。
- 1.静态代理实现简单,只要代理对象类与被代理对象类都去实现一个共同的接口就可以对目标对象进行增强功能。但是很麻烦,功能有限,拥有局限性。
- 2.JDK动态代理需要被代理对象去实现业务接口,代理类只需要实现InvocationHandler接口。
- 3.静态代理类编译期生成class文件,直接使用,效率高。
- 4.JDK动态代理通过反射,比较消耗系统性能,但减少代理类的数量,使用灵活。
- 5.CGLIB动态代理不需要实现接口,通过生成字节码实现代理,比反射快,但会继承目标对象从而去增强,所以要求目标对象不能为final修饰。

- Spring的AOP用了两种动态代理,利用反射生成类快以及ASM在执行过程比较快二者的优点进行结合。避免了反射执行过程比较慢以及ASM在生成对象时也慢。从而实现了AOP。

关于ASM可以点击https://blog.csdn.net/conquer0715/article/details/51283610查看。

用户评论