一.代理模式
1.概念
代理模式(Proxy Pattern )是指为其他对象提供一种代理,以控制对这个对象的访问,属于结构型模式。
在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。
2.代理模式三种角色
2.1 抽象角色( Subject ): 抽象主题类的主要职责是声明真实主题与代理的共同接口方法,该类可以是接口也可以是抽象类
2.2 真实角色(RealSubiect ): 该类也被称为被代理类,该类定义了代理所表示的真实对象,是负责执行系统真正的逻辑业务对象:
2.3 代理角色 ( Proxy): 也被称为代理类,其内部持有 RealSubiect 的用,因此具备完全的对RealSubiect 的代理权。客户端调用代理对象的方法,同时也调用被代理对象的方法,但是会在代理对象前后增加一些处理代码。
二.代理模式的通用写法
2.1 创建一个抽象角色:用于代理和真实对象共同接口方法。
public interface ISubject {
void request();
}
2.2 创建一个真实角色:用于执行真正的业务逻辑处理。
public class RealSubject implements ISubject {
public void request() {
System.out.println("real service is called.");
}
}
2.3 创建一个代理角色:调用真实业务逻辑时候前后自己处理逻辑代码。
public class Proxy implements ISubject {
//1.获取真实对象封装处理
private ISubject subject;
public Proxy(ISubject subject){
this.subject = subject;
}
//2.调用真实对象业务逻辑,前后加一些自己逻辑增强处理。
public void request() {
before();
subject.request();
after();
}
//3.前后增加逻辑处理
public void before(){
System.out.println("called before request().");
}
public void after(){
System.out.println("called after request().");
}
}
2.4 测试功能
public class Client {
public static void main(String[] args) {
//创建代理对象并绑定一个真实对象
Proxy proxy = new Proxy(new RealSubject());
//执行代理对象功能调用
proxy.request();
}
}
//--结果处理------------
called before request().
real service is called.
called after request().
三.静态代理到动态代理
1.抽取角色:定义一个接口用于真实和代理对象共同的接口方法
//定义人的接口,相亲接口方法
public interface IPerson {
void findLove();
}
2.真是角色:创建一个真正的人的对象并实现相亲接口方法具体逻辑
//定义一个张三人对象并提出相亲的要求
public class ZhangSan implements IPerson {
public void findLove() {
System.out.println("张三:要求相亲女孩长得好看又善良");
}
}
3.代理角色:创建一个代理张三对象(张三的父亲)代理完成张三的相亲要求。
public class ZhangLaosan implements IPerson {
//---静态代理------------------------
//1.创建获取静态代理对象处理【只能接受张三这个人,其他人不能接受】
private ZhangSan zhangsan;
public ZhangLaosan(ZhangSan zhangsan) {
this.zhangsan = zhangsan;
}
//2.完成张三的相亲,并在相亲的前后做一些工作和处理。
public void findLove() {
System.out.println("张老三开始物色");
zhangsan.findLove();
System.out.println("开始交往");
}
//---动态代理------------------------
//1.创建获取动态代理对象处理【只要实现抽象角色的接口,任何真实对象都可以接受并执行代理逻辑】
private IPerson person;
public ZhangLaosan(IPerson person) {
this.person = person;
}
//2.完成张三的相亲,并在相亲的前后做一些工作和处理。
public void findLove() {
System.out.println("张老三开始物色");
person.findLove();
System.out.println("开始交往");
}
}
4.测试代码
public class Test {
public static void main(String[] args) {
ZhangLaosan zhangLaosan = new ZhangLaosan(new ZhangSan());
zhangLaosan.findLove();
}
}
结果:
张老三开始物色
张三:要求相亲女孩长得好看又善良
开始交往
四. JDKProxy动态代理
1.抽取角色:定义一个接口用于真实和代理对象共同的接口方法
public interface IPerson {
void findLove();
}
2.真是角色:创建一个真正的人的对象并实现相亲接口方法具体逻辑
//定义一个张三人对象并提出相亲的要求
public class ZhangSan implements IPerson {
public void findLove() {
System.out.println("张三:要求相亲女孩长得好看又善良");
}
}
3.代理角色:创建一个代理张三对象(张三的父亲)代理完成张三的相亲要求。
public class JdkMeipo implements InvocationHandler {
//1.定义接受真实对象变量
private IPerson target;
public IPerson getInstance(IPerson target){
this.target = target; //真实对象赋值
//clazz.getClassLoader():真实对象反射类对象(可以通过目标类的getClassLoader()方法来获取目标类的ClassLoader对象)
//clazz.getInterfaces():真实对象接口列表 (Class[]对象,代理类要实现的接口列表。代理类将会实现这些接口,并且可以调用接口中定义的方法)
//this:真实对象(InvocationHandler接口的实现类对象,代理类在调用方法时会委托给该InvocationHandler对象来处理)
Class<?> clazz = target.getClass();
return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(this.target,args);
after();
return result;
}
private void after() {
System.out.println("双方同意,开始交往");
}
private void before() {
System.out.println("我是媒婆,已经收集到你的需求,开始物色");
}
}
4.测试
public class Test {
public static void main(String[] args) {
JdkMeipo jdkMeipo = new JdkMeipo();//创建一个代理对象
IPerson zhangsan = jdkMeipo.getInstance(new Zhangsan());//把真实对象代理处理一个代理张三的对象
zhangsan.findLove();
}
}
结果:
张老三开始物色
张三:要求相亲女孩长得好看又善良
开始交往
五. CGlib动态代理
依赖maven cglib库
cglib
cglib-nodep
2.2
1.定义真实对象类并写真实的业务逻辑处理。
public class Customer {
public void findLove(){
System.out.println("儿子要求:肤白貌美大长腿");
}
}
2.定义代理对象
public class CGlibMeipo implements MethodInterceptor {
//1.定义接受真实对象处理,返回一个代理对象
public Object getInstance(Class<?> clazz) throws Exception{
//相当于Proxy,代理的工具类
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/*
o:被代理的对象。即原始对象,也就是目标类的实例。
method:要被调用的方法对象。即将要执行的目标方法。
objects:方法的参数数组。即目标方法的参数列表。
methodProxy:方法的代理对象。通过该对象可以调用目标方法。使用methodProxy.invokeSuper(o, objects)可以触发目标方法的执行。
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o,objects);
after();
return obj;
}
private void before(){
System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
System.out.println("开始物色");
}
private void after(){
System.out.println("OK的话,准备办事");
}
}
3.测试
public class CglibTest {
public static void main(String[] args) {
try {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E://cglib_proxy_classes");//打印代理对象生成的class文件
//CGlibMeipo代理对象绑定真实对象并返回代理对象
Customer obj = (Customer) new CGlibMeipo().getInstance(Customer.class);
//执行代理对象方法并调用真实对象
obj.findLove();
} catch (Exception e) {
e.printStackTrace();
}
}
}
六. 代理模式的优缺点
代理模式具有以下优点
(1)代理模式能将代理对象与真实被调用目标对象分离
(2)在一定程度上降低了系统的耦合性,扩展性好
(3)可以起到保护目标对象的作用
(4)可以增强目标对象的功能
当然,代理模式也有缺点
( 1)代理模式会造成系统设计中类的数量增加
(2)在客户端和目标对象中增加一个代理对象,会导致请求处理速度变慢.
(3)增加了系统的复杂度文章来源:https://www.toymoban.com/news/detail-796388.html
七. JDK Proxy和CGLib比较
JDK是采用读取接口的信息
CGLib覆盖父类方法
目的:都是生成一个新的类,去实现增强代码逻辑的功能
JDK Proxy 对于用户而言,必须要有一个接口实现,目标类相对来说复杂
CGLib 可以代理任意一个普通的类,没有任何要求
CGLib 生成代理逻辑更复杂,效率,调用效率更高,生成一个包含了所有的逻辑的FastClass,不再需要反射调用
JDK Proxy生成代理的逻辑简单,执行效率相对要低,每次都要反射动态调用
CGLib 有个坑,CGLib不能代理final的方法文章来源地址https://www.toymoban.com/news/detail-796388.html
到了这里,关于3_代理模式(动态代理JDK原生和CGLib)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!