代理模式
介绍
代理模式的定义:通过一些代理对象来控制访问目标对象,访问者不会直接访问目标对象,而是通过代理类来进行访问,代理类是访问者和目标对象之间的桥梁。
在我们生活中,比如我们要去买房子,我们不可能直接去看房子,必须要通过房地产经销商来推荐和介绍,我们才能买到理想中的房子,在这个例子里,房地产经销商就是类似一个代理类,房子就是目标类,而我们买房子的人就是访问类。类似的例子还有很多,比如各种产品的代理商等等
代理模式的主要角色如下。
- 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
- 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
- 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
静态代理
静态代理很简单,我们只需要在目标类外面嵌套一个类,将这个类暴露给外面的访问者就可以了,代码如下:
接口:
package com.example.demo.design.proxy.stat;
/**
* 定义业务方法接口
*/
public interface Role {
public void getGift();
}
目标类:
package com.example.demo.design.proxy.stat;
/**
* @author: sunzhinan
* @create: 2020-08-08 18:02
* @description: 具体业务实现类
*/
public class Celebrity implements Role{
@Override
public void getGift() {
System.out.println("获得礼物了!");
}
}
代理类:
package com.example.demo.design.proxy.stat;
/**
* @author: sunzhinan
* @create: 2020-08-08 18:03
* @description: 代理类
*/
public class RoleProxy {
private Role role;
public RoleProxy(Role role) {
this.role = role;
}
public void getGift(){
System.out.println("代理开始");
role.getGift();
System.out.println("代理结束");
}
}
测试:
package com.example.demo.design.proxy.stat;
/**
* @author: sunzhinan
* @create: 2020-08-08 18:05
* @description: 测试类
*/
public class TestProxy {
public static void main(String[] args) {
RoleProxy roleProxy = new RoleProxy(new Celebrity());
roleProxy.getGift();
}
}
结果:
代理开始
获得礼物了!
代理结束
如果有多个代理类嵌套,可以通过下面的方式:
代理类1:
package com.example.demo.design.proxy.stat;
/**
* @author: sunzhinan
* @create: 2020-08-08 18:03
* @description: 代理类
*/
public class RoleProxy implements Role{
private Role role;
public RoleProxy(Role role) {
this.role = role;
}
public void getGift(){
System.out.println("代理开始");
role.getGift();
System.out.println("代理结束");
}
}
代理类2:
package com.example.demo.design.proxy.stat;
/**
* @author: sunzhinan
* @create: 2020-08-08 18:48
* @description: 代理类
*/
public class RoleMethodProxy implements Role{
private Role role;
public RoleMethodProxy(Role role) {
this.role = role;
}
@Override
public void getGift() {
System.out.println("新的代理开始");
role.getGift();
System.out.println("新的代理结束");
}
}
测试类:
package com.example.demo.design.proxy.stat;
/**
* @author: sunzhinan
* @create: 2020-08-08 18:05
* @description: 测试类
*/
public class TestProxy {
public static void main(String[] args) {
RoleProxy roleProxy = new RoleProxy(new Celebrity());
RoleMethodProxy roleMethodProxy = new RoleMethodProxy(roleProxy);
roleMethodProxy.getGift();
}
}
结果:
新的代理开始
代理开始
获得礼物了!
代理结束
新的代理结束
个人觉得,静态代理在实际运用中可能会很少出现,因为它有个很明显的弊端,不可能在每个业务目标类外面都嵌套个代理类,这样代码会非常的冗余,同时,如果目标类发生改变,那么代理类也需要做相应的修改,显然这不是一个很好的方法。
动态代理
使用动态代理,我们不需要在项目开发过程中自己手动创建代理类,而是由JDK在运行的时候为我们动态的来创建,这里是通过动态处理类来生成代理类。需要使用到InvocationHandler以及Proxy类的newProxyInstance方法
接口:
package com.example.demo.design.proxy.dynamic;
/**
* 定义业务方法接口
*/
public interface Role {
public void getGift();
public void getLife();
}
目标类:
package com.example.demo.design.proxy.dynamic;
/**
* @author: sunzhinan
* @create: 2020-08-08 18:02
* @description: 具体业务实现类
*/
public class Celebrity implements Role {
@Override
public void getGift() {
System.out.println("获得礼物了!");
}
@Override
public void getLife() {
System.out.println("获得life!");
}
}
动态代理类:
package com.example.demo.design.proxy.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author: sunzhinan
* @create: 2020-08-08 18:19
* @description: 动态代理类
*/
public class ProxyHandler implements InvocationHandler {
private Object targetObj;
public Object newProxyInstance(Object targetObj) {
this.targetObj = targetObj;
return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(),
targetObj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理开始");
Object obj = method.invoke(targetObj,args);
System.out.println("代理结束");
return obj;
}
}
测试类:
package com.example.demo.design.proxy.dynamic;
/**
* @author: sunzhinan
* @create: 2020-08-08 19:43
* @description: 测试类
*/
public class TestProxy {
public static void main(String[] args) {
ProxyHandler handler = new ProxyHandler();
Role role = (Role) handler.newProxyInstance(new Celebrity());
role.getGift();
System.out.println("------------");
role.getLife();
}
}
结果:
代理开始
获得礼物了!
代理结束
------------
代理开始
获得life!
代理结束
与静态代理比较,动态代理不需要对目标类中的每个方法进行重复的代理,可以统一处理,所以动态代理的应用会使我们的代码更加简单,复用性强。
Cglib代理
Cglib代理需要额外引入一个jar包,但是如果你项目使用的Spring,那么就可以直接使用,因为Spring的AOP也有的是基于Cglib代理(JDK动态代理与CGLib动态代理均是实现Spring AOP的基础)。那么动态代理和Cglib代理的区别就是,动态代理需要目标类通过接口定义业务方法,对于没有接口的类,那该如何代理呢,而Cglib可以解决没有实现接口类的代理。但Cglib采用的是继承,所以不能对final修饰的类进行代理。
接口:
package com.example.demo.design.proxy.cglib;
/**
* 定义业务方法接口
*/
public interface Role {
public void getGift();
public void getLife();
}
目标类:
package com.example.demo.design.proxy.cglib;
/**
* @author: sunzhinan
* @create: 2020-08-08 18:02
* @description: 具体业务实现类
*/
public class Celebrity implements Role {
@Override
public void getGift() {
System.out.println("获得礼物了!");
}
@Override
public void getLife() {
System.out.println("获得life!");
}
}
Cglib代理类
package com.example.demo.design.proxy.cglib;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author: sunzhinan
* @create: 2020-08-08 21:45
* @description: 代理类
*/
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代理开始!");
Object object = methodProxy.invokeSuper(o,objects);
System.out.println("代理结束!");
return object;
}
}
测试类:
package com.example.demo.design.proxy.cglib;
import org.springframework.cglib.proxy.Enhancer;
/**
* @author: sunzhinan
* @create: 2020-08-08 21:43
* @description: 测试类
*/
public class TestProxy {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Celebrity.class);
enhancer.setCallback(new MyMethodInterceptor());
Celebrity celebrity = (Celebrity) enhancer.create();
celebrity.getGift();
System.out.println("-------------");
celebrity.getLife();
}
}
结果:
代理开始!
获得礼物了!
代理结束!
-------------
代理开始!
获得life!
代理结束!