免费建个人手机网站,WordPress 简历库,wordpress编辑文字空白卡主,天津旅游网站建设前言
代理模式是一种设计模式#xff0c;能够使得在不修改源目标的前提下#xff0c;额外扩展源目标的功能。即通过访问源目标的代理类#xff0c;再由代理类去访问源目标。这样一来#xff0c;要扩展功能#xff0c;就无需修改源目标的代码了。只需要在代理类上增加就可…前言
代理模式是一种设计模式能够使得在不修改源目标的前提下额外扩展源目标的功能。即通过访问源目标的代理类再由代理类去访问源目标。这样一来要扩展功能就无需修改源目标的代码了。只需要在代理类上增加就可以了。 其实代理模式的核心思想就是这么简单在java中代理又分静态代理和动态代理2种其中动态代理根据不同实现又区分基于接口的的动态代理和基于子类的动态代理。
其中静态代理由于比较简单面试中也没啥问的在代理模式一块问的最多就是动态代理而且动态代理也是spring aop的核心思想spring其他很多功能也是通过动态代理来实现的比如拦截器事务控制等。
熟练掌握动态代理技术能让你业务代码更加精简而优雅。如果你需要写一些中间件的话那动态代理技术更是必不可少的技能包。
静态代理
静态代理就是通过声明一个明确的代理类来访问源对象。
我们有1个接口Person。这个个接口各有2个实现类UML如下图
实现
接口:person.java
package StaticProxy;/*** author zyz* version 1.0* data 2023/2/15 13:29* Description:*/
public interface Person {/*** 起床*/public void wakeup();/*** 睡觉*/public void sleep();
}
实现类:Student .java
package StaticProxy;/*** author zyz* version 1.0* data 2023/2/15 13:32* Description:*/
public class Student implements Person{private String name;public Student(){}public Student(String name){this.name name;}Overridepublic void wakeup() {System.out.println(学生name起床了);}Overridepublic void sleep() {System.out.println(学生name睡觉了);}
}
假设我们现在要做一件事就是在所有的实现类调用wakeup()前增加一行输出早安调用sleep()前增加一行输出晚安。那我们只需要编写1个代理类PersonProxy
代理类PersonProxy .java
package StaticProxy;/*** author zyz* version 1.0* data 2023/2/15 13:35* Description:*/
public class PersonProxy implements Person{private Person person;public PersonProxy(Person person){this.person person;}Overridepublic void wakeup() {System.out.println(早上好啊!!!);person.wakeup();}Overridepublic void sleep() {System.out.println(晚上好啊!!!);person.sleep();}
}
测试类
package StaticProxy;/*** author zyz* version 1.0* data 2023/2/15 13:37* Description:*/
public class Test {public static void main(String[] args) {Person student1 new Student(张三);PersonProxy studentProxy new PersonProxy(student1);studentProxy.wakeup();studentProxy.sleep();}
}
结果 结论
静态代理的代码相信已经不用多说了代码非常简单易懂。这里用了1个代理类代理了Person接口。
这种模式虽然好理解但是缺点也很明显
会存在大量的冗余的代理类这里演示了1个接口如果有10个接口就必须定义10个代理类。不易维护一旦接口更改代理类和目标类都需要更改。
动态代理
动态代理通俗点说就是无需声明式的创建java代理类而是在运行过程中生成虚拟的代理类被ClassLoader加载。从而避免了静态代理那样需要声明大量的代理类。
JDK从1.3版本就开始支持动态代理类的创建。主要核心类只有2个java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler。
还是前面那个例子用JDK动态代理类去实现的代码如下
创建一个JdkProxy类用于统一代理
package DynamicProxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;/*** author zyz* version 1.0* data 2023/2/15 13:28* Description:*/
public class JdkProxy implements InvocationHandler {private Object bean;public JdkProxy(Object bean) {this.bean bean;}/*** 其中proxy为代理过之后的对象(并不是原对象)method为被代理的方法args为方法的参数。** 如果你不传原有的bean直接用method.invoke(proxy, args)的话那么就会陷入一个死循环。* param proxy* param method* param args* return* throws Throwable*/Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {String methodName method.getName();if (methodName.equals(wakeup)) {System.out.println(早安~~~);} else if (methodName.equals(sleep)) {System.out.println(晚安~~~);}return method.invoke(bean, args);}
}
测试
package DynamicProxy;import StaticProxy.Person;
import StaticProxy.Student;import java.lang.reflect.Proxy;/*** author zyz* version 1.0* data 2023/2/15 13:46* Description:*/
public class Test {public static void main(String[] args) {JdkProxy proxy new JdkProxy(new Student(李四));Person student (Person) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Person.class}, proxy);student.wakeup();student.sleep();}
}
结果 可以看到相对于静态代理类来说无论有多少接口这里只需要一个代理类。核心代码也很简单。唯一需要注意的点有以下2点
JDK动态代理是需要声明接口的创建一个动态代理类必须得给这个”虚拟“的类一个接口。可以看到这时候经动态代理类创造之后的每个bean已经不是原来那个对象了。
这里JdkProxy最核心的方法就是
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable其中proxy为代理过之后的对象(并不是原对象)method为被代理的方法args为方法的参数。
如果你不传原有的bean直接用method.invoke(proxy, args)的话那么就会陷入一个死循环。