设计模式
设计模式是一套被反复使用的,多数人知晓的,经过分类编目的代码设计经验的总结
使用设计模式是为了重用代码,让代码更容易的让人理解,保证代码的可靠性
代理模式:
代理类和委托类有共同的接口
代理类主要是为委托类预处理消息,过滤消息,把消息传给委托类,以及事后处理消息等
代理类对象并不真正实现服务,而是通过委托类的相关方法来提供特点的服务.所有我们在访问实际对象时,是通过代理对象来访问的
代理模式分为两种:
<1>静态代理
代理类与被代理类的依赖关系在编译期间就确定了
CarInter
public interface CarInter {
public abstract void makeCar(); //造车
public abstract void washCar(); //洗车
public abstract void fixCar(); //修车
}
CarFactory.java
package com.xalo.staticproxy;
//委托方
public class CarFactory implements CarInter {
@Override
public void makeCar() {
System.out.println("委托者造车方法");
}
@Override
public void washCar() {
System.out.println("委托者洗车方法");
}
@Override
public void fixCar() {
System.out.println("委托者修车方法");
}
}
ProxyCar.java
package com.xalo.staticproxy;
//代理方: 为委托方的功能添加额外功能,并且还不影响委托方中的代码结构
public class ProxyCar implements CarInter {
//通知对象
private static MyAdvice advice = new MyAdvice();
// 委托者对象
private CarInter carFactory;
public ProxyCar(){
}
public ProxyCar(CarInter carFactory) {
this.carFactory = carFactory;
}
@Override
public void makeCar() {
advice.before();
// 基本功能
this.carFactory.makeCar();
}
@Override
public void washCar() {
this.carFactory.washCar();
advice.after();
}
@Override
public void fixCar() {
try {
advice.around("fixCar", carFactory.getClass());
} catch (Exception e) {
e.printStackTrace();
}
}
}
MyAdvice.java
package com.xalo.staticproxy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyAdvice {
public void before() {
System.out.println("前置通知");
}
public void after() {
System.out.println("后置通知");
}
// 第一个参数: 要增强的方法 第二个参数: 代理对象的class对象
public void around(String method, Class pc) throws NoSuchMethodException,
SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException, InstantiationException {
System.out.println("环绕增强开始");
// 得到该执行的方法
Method meth = pc.getMethod(method, null);
// 执行该方法
meth.invoke(pc.newInstance(), null);
System.out.println("环绕增强结束");
}
}
MyTest.java
public class MyTest {
@Test
public void test() {
//不使用代理模式
CarFactory carFactory = new CarFactory();
carFactory.makeCar();
// 静态代理模式
// //使用代理
ProxyCar car = new ProxyCar(carFactory);
car.makeCar();
car.washCar();
car.fixCar();
}
控制台测试打印结果
<2>动态代理
代理类和被代理类的依赖关系是在运行时确定的
InvocationHandler接口: 给动态代理类实现的,负责被代理对象的操作
Proxy类: 创建动态代理类实例对象的
(1)JDK动态代理实现原理:
JDK动态代理的实现是依赖于接口的,首先使用接口来定义好操作规范.
然后通过Proxy类产生的代理对象Proxy去调用被代理对象的操作.
而这个操作又被分发给InvocationHandler接口的invoke方法具体执行
CigaretteInter
public interface CigaretteInter {
public abstract void makeCigarette();
}
Cigarette.java
public class Cigarette implements CigaretteInter {
@Override
public void makeCigarette() {
System.out.println("委托者造烟方法");
}
}
DynamicProxy.java
/*
* 委托方是在运行时确定
* 动态代理: JDK提供的接口实现 JDK动态代理内部实现是基于接口的
* AOP使用的动态代理:CGlib CGlib动态代理内部实现还是基于委托对象
*/
public class DynamicProxy implements InvocationHandler {
//目标对象
private Object targetObj;
public DynamicProxy() {
}
public DynamicProxy(Object targetObject){
this.targetObj = targetObject;
}
//将委托方和代理方建立动态的联系
//返回值为代理对象
public Object instance(){
/*
* 第一个参数: 对象的加载器(ClassLoader),在JVM中将 .java源文件进行编译,就生成 .class文件 通过 .class文件创建当前实例对象
* 第二个参数: 目标对象的所有的接口方法
* 第三个参数: 代理对象 委托方- 委托方所有的接口方法-代理方
*/
return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(), targetObj.getClass().getInterfaces(), this);
}
/*
* 当代理对象调用委托对象的接口方法时,并不是立即执行,而是执行invoke方法
* 第一个参数: 代理对象
* 第二个参数: 需要执行的方法
* 第三个参数:需要执行的方法的实参
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置通知");
//method方法的返回值,不明确委托方是谁,返回值为Object
Object object = method.invoke(targetObj, args);
System.out.println("后置通知");
return object;
}
}
MyTest.java
// 动态代理模式
CarFactory carFactory = new CarFactory();
DynamicProxy dynamicProxy = new DynamicProxy(carFactory);
// 进行动态绑定
CarInter object = (CarInter) dynamicProxy.instance();
object.washCar();
//动态代理模式
Cigarette cigarette = new Cigarette();
DynamicProxy dynamicProxy = new DynamicProxy(cigarette);
//进行动态绑定
CigaretteInter object = (CigaretteInter) dynamicProxy.instance();
object.makeCigarette();
控制台测试打印结果
(2)CGlib动态代理: 对没有实现接口的类做动态代理
是一个强大的,高性能的Code生成类库,可以在程序运行期间动态扩展类或者接口,它的底层是使用java字节码操作框架ASM实现
代理原理:
动态生成一个代理类的子类,子类要重写代理类的所有不是final的方法.在子类中采用方法拦截的技术,拦截所有父类方法的调用,顺势织入横切逻辑
1.导入 cglib-nodep-3.2.6jar
2.定义业务类,被代理的类没有实现任何接口
3.定义拦截器: 在调用目标方法时,cglib会回调MethodIntercetor接口方法拦截,来实现你自己的代理逻辑(类似于JDK中的 InvocationHandler接口)
4.定义动态代理工厂,代理动态代理
5.客户端调用