代理模式是在不修改源目标的前提下,额外扩展源目标的功能。
即通过访问源目标的代理类,再由代理类去访问源目标。这样一来,要扩展功能,就无需修改源目标的代码了。只需要在代理类上增加就可以了。
如上图所示:访问者通过上图 1 的方式,替换 2 的方式。保留源目标类方法不动的情况下,实现起拓展功能。
2、代理模式类别下书代码实例,是我们创建的一个确定接口及对应的实现类,作为源目标类。
public interface Person {
void wakeUp();
void sleep();
}
public class Student implements Person {
private String name;
public Student() { }
public Student(String name) {
this.name = name;
}
public void wakeUp() {
System.out.println( " Good morning " + name);
}
public void sleep() {
System.out.println(" Good evening " + name);
}
}
2.1、静态代理
静态代理即声明一个明确的代理类,来拓展源目标的方法。
public class StudentProxy implements Person {
private Person person;
public StudentProxy(Person person) {
this.person = person;
}
public void wakeUp() {
System.out.print(" 我是静态代理 wakeUp ");
this.person.wakeUp();
}
public void sleep() {
System.out.print(" 我是静态代理 Sleep ");
this.person.sleep();
}
public static void main(String[] args) {
Person student = new Student("王大拿");
Person person = new StudentProxy(student);
student.wakeUp();
student.sleep();
person.wakeUp();
person.sleep();
}
}
输出结果:
Good morning 王大拿
Good evening 王大拿
我是静态代理 wakeUp Good morning 王大拿
我是静态代理 Sleep Good evening 王大拿
静态代理缺点:
- 会存在大量的冗余的代理类,这里演示了1个接口,如果有10个接口,就必须定义10个代理类。
- 不易维护,一旦接口更改,代理类和目标类都需要更改。
动态代理, 即无需声明式的创建java代理类,而是在运行过程中生成"虚拟"的代理类,被ClassLoader加载。
2.2.1、jdk动态代理 2.2.1.1、实现方式一 java.lang.reflect.InvocationHandlerpublic class JDKProxy implements InvocationHandler {
private Object object ;
public JDKProxy(Object object) {
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if(methodName.equals("wakeUp")){
System.out.print(" 我是JDK动态代理 wakeUp ");
}else if (methodName.equals("sleep")){
System.out.print(" 我是JDK动态代理 sleep ");
}
return method.invoke(object , args);
}
public static void main(String[] args) {
JDKProxy proxy1 = new JDKProxy(new Student("刘星星"));
Person person = (Person) Proxy.newProxyInstance(proxy1.getClass().getClassLoader(), new Class[]{Person.class}, proxy1);
person.wakeUp();
person.sleep();
}
}
输出结果:
我是JDK动态代理 wakeUp Good morning 刘星星
我是JDK动态代理 sleep Good evening 刘星星
可以看到被代理后Person的Bean对应的是代理实体类为Proxy
2.2.2.1.2 实现方式二 java.lang.reflect.Proxypublic class JDKProxy2 {
private Object object;
public Object getProxy() {
Object proxy = Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if ("wakeUp".equals(methodName)) {
System.out.print("我是JDk动态代理2 wakeUp ");
} else if ("sleep".equals(methodName)) {
System.out.print("我是JDk动态代理2 sleep ");
}
return method.invoke(object, args);
}
});
return proxy;
}
public JDKProxy2(Object object) {
this.object = object;
}
public static void main(String[] args) {
Student student = new Student("大西瓜");
JDKProxy2 proxy2 = new JDKProxy2(student);
Person person = (Person) proxy2.getProxy();
person.wakeUp();
person.sleep();
}
}
输出结果:
我是JDk动态代理2 wakeUp Good morning 大西瓜
我是JDk动态代理2 sleep Good evening 大西瓜
2.2.2、cglib动态代理
Spring在5.X之前默认的动态代理实现一直是jdk动态代理。但是从5.X开始,spring就开始默认使用Cglib来作为动态代理实现。并且springboot从2.X开始也转向了Cglib动态代理实现。
Cglib是一个开源项目,它的底层是字节码处理框架ASM,Cglib提供了比jdk更为强大的动态代理。主要相比jdk动态代理的优势有:
jdk动态代理只能基于接口,代理生成的对象只能赋值给接口变量,而Cglib就不存在这个问题,Cglib是通过生成子类来实现的,代理对象既可以赋值给实现类,又可以赋值给接口。
Cglib速度比jdk动态代理更快,性能更好
public class CGLibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
private Object bean;
public CGLibProxy(Object bean) {
this.bean = bean;
}
public Object getProxy() { //设置需要创建子类的类
enhancer.setSuperclass(bean.getClass());
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
//实现MethodInterceptor接口方法
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
String methodName = method.getName();
if (methodName.equals("wakeUp")) {
System.out.print("我是cglib动态代理 wakeUp ");
} else if (methodName.equals("sleep")) {
System.out.print("我是cglib动态代理 sleep ");
} //调用原bean的方法
return method.invoke(bean, args);
}
public static void main(String[] args) {
CGLibProxy proxy = new CGLibProxy(new Student("陈鹏鹏"));
Student student = (Student) proxy.getProxy();
student.wakeUp();
student.sleep();
}
}
输出结果:
我是cglib动态代理 wakeUp Good morning 陈鹏鹏
我是cglib动态代理 sleep Good evening 陈鹏鹏
cglib包引入:
<dependency>
<groupId>cglibgroupId>
<artifactId>cglibartifactId>
<version>3.3.0version>
dependency>
代理模式是技术迭代的核心,组件开发的重中之重
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)