代理模式
设计模式之简单讨论
1:代理模式
意图:对其他对象提供一种代理以控制对这个对象的访问。例如 律师
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
2:代理模式的UML图

从UML图中,可以看出代理类与真正实现的类都是继承了抽象的主题类,这样的好处在于代理类可以与实际的类有相同的方法,可以保证客户端使用的透明性。
3:代理模式的实现
代理模式可以有两种实现的方式,一种是静态代理类,另一种是动态代理
静态代理代码示例如下
Subject接口的实现
public interface Subject {
void visit();
}
实现了Subject接口的两个类:
public class RealSubject implements Subject {
private String name = "xpfuser";
@Override
public void visit() {
System.out.println(name);
}
}
public class ProxySubject implements Subject{
private Subject subject;
public ProxySubject(Subject subject) {
this.subject = subject;
}
@Override
public void visit() {
subject.visit();
}
}
具体的调用如下:
public class Client {
public static void main(String[] args) {
ProxySubject subject = new ProxySubject(new RealSubject());
subject.visit();
}
}
通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。同时符合开闭原则但是也有缺点,每一个代理类都必须实现一遍委托类(也就是realsubject)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。
静态代理模式的特点:一个主题类与一个代理类一一对应
4:动态代理
动态代理也分为两种:JDK代理、CGLIB代理
4.1:JDK代理实现
核心技术 反射、接口
//1. 抽象主题
public interface Moveable {
void move() throws Exception;
}
//2. 真实主题
public class Car implements Moveable {
public void move() throws Exception {
Thread.sleep(new Random().nextInt(1000));
System.out.println("汽车行驶中…");
}
}
//3.事务处理器
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
/**
* 参数:
*proxy 被代理的对象
*method 被代理对象的方法
*args 方法的参数
* 返回:
*Object 方法返回值
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start-time = System.currentTimeMillis();
System.out.println("汽车开始行驶…");
method.invoke(target, args);
long stopTime = System.currentTimeMillis();
System.out.println("汽车结束行驶…汽车行驶时间:" + (stopTime - startTime) + "毫秒!");
return null;
}
}
//测试类
public class Test {
public static void main(String[] args) throws Exception{
//真实主题
Car car = new Car();
//获取InvocationHandler
InvocationHandler h = new TimeHandler(car);
//获取真实主题的class
Class<?> cls = car.getClass();
/**
*loader 类加载器
*interfaces 实现接口
*h InvocationHandler
*/
//Moveable m 这个对象已经是被jvm修饰过的 已经不再是真实意义上的Moveable 类型。是Moveable 类型的代理类。可以在调用自己方法时 回调到动态代理类 TimeHandler的invoke方法 已完成动态代理
Moveable m = (Moveable) Proxy.newProxyInstance
(cls.getClassLoader(),cls.getInterfaces(), h);
//调用方法 此时会真正的执行TimeHandler 的invoke方法
m.move(); }
}
JDK动态代理步骤
1.创建一个实现InvocationHandler接口的类,它必须实现invoke()方法
2.创建被代理的类及接口
3.调用Proxy的静态方法,创建一个代理类
4.通过代理调用方法
4.2:CGLIB代理:
继承式代理
有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做Cglib代理。
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展。Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,为其提供方法的interception(拦截),例如大家所熟知的Spring AOP。
特点:
1.代理的类不能为final,否则报错
2.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.
public class test {
public static void main(String[] args) {
//目标对象
UserDao target = new UserDao();
//代理对象
UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();
//执行代理对象的方法
proxy.save();
}
}
/**
* 目标对象,没有实现任何接口
*/
class UserDao {
public void save() {
System.out.println("----已经保存数据!----");
}
}
/**
* Cglib子类代理工厂
* 对UserDao在内存中动态构建一个子类对象
*/
class ProxyFactory implements MethodInterceptor {
// 维护目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// 给目标对象创建一个代理对象
public Object getProxyInstance() {
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("开始事务...");
// 执行目标对象的方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事务...");
return returnValue;
}
}
5:Spring注解实现AOP (简单高效)
5.1:pom引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
5.2:创建个controller

5.3:创建一个aspect切面类

启动aspl项目并测试 分析整个执行过程
浙公网安备 33010602011771号