代理模式的参与者:
- 目标对象
- 代理对象
通过代理模式来增强对象的:增强参数列表 、返回值类型 、方法体
例如添加日志系统,验证功能,这也是面向切面编程的思想。
代理模式的实现方式:
静态代理:
简单说就是重定义一个类来增强目标对象
package com.proxy;
public class StaticProxy {
public static void main(String[] args) {
//1. 目标对象
BuyCar buyCar = new BuyCar();
//2. 代理对象
BuyProxy buyProxy = new BuyProxy(buyCar);
//3. 调用代理对象方法
buyProxy.buy("car");
}
}
//目标对象的接口
interface BuySome {
String buy(String name);
}
/**
* 目标对象
*/
class BuyCar implements BuySome {
@Override
public String buy(String name) {
System.out.println("buy " + name);
return "ok";
}
}
/**
* 代理对象
*/
class BuyProxy implements BuySome {
//接收目标对象
private BuySome buySome;
public BuyProxy( final BuySome buySome){
this.buySome = buySome;
}
@Override
public String buy(String name) {
System.out.println("付钱");
return buySome.buy(name);
}
}
- 静态代理总结:
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们为每一个目标对象,都得书写一个代理对象
在上述代码中: 对于BuyCar类,我们需要写一个BuyProxy类来进行代理
这样整个过程 存在一个接口,两个实现类
动态代理:在内存中代理形成代理类
1. 代理对象和真实对象有相同的接口
2. 代理对象 使用 Proxy.newInstance()来动态创建
package com.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
Customer customer = new Customer();
/**
* 参数
* 1. 真实对象 class
* 2. 真实对象 interface
* 3. new InvocationHandler() 处理器
*/
ProxyCustomer proxy = (ProxyCustomer)Proxy.newProxyInstance(customer.getClass().getClassLoader(),
customer.getClass().getInterfaces(), new InvocationHandler() {
@Override
/**
* 1. proxy 代理(目标)对象
* 2. method 代理(目标)对象封装的方法类
* 3. args 代理对象调用方法时的参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 目标对象的buy方法
if(method.getName().equals("buy")){
//1. 增强参数 对参数进行处理之类的操作
//double money = (double) args[0];
//增强方法 在业务逻辑中加入 日志,验证过程等
System.out.println("付钱过程");
//使用真实对象调用方法
Object object = method.invoke(customer, args);
//增强返回值 对返回值进行封装等操作
return object.toString();
} else{
return null;
}
}
});
System.out.println(proxy.buy(" 汽车 "));
}
}
//目标对象
class Customer implements ProxyCustomer{
public String buy(String name){
System.out.println("购买 " + name);
return "ds";
}
}
//目标对象的接口
interface ProxyCustomer{
String buy(String name);
}
- 动态代理总结:
- 优点:动态生成代理对象,脱离了对代理对象的依赖,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度
在代码中我们值建立了一个接口,一个对象比静态代理少了一个类 - 缺点:Jdk动态代理仅支持interface代理的,不能用于没有父接口的类
CGLIB代理:实现对class的动态代理
- 原理:CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑,但因为采用的是继承,所以不能对final修饰的类进行代理。
package com.proxy;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* CGLIB动态代理
*/
public class CglibProxy {
public static void main(String[] args) {
//1. 目标对象
BuyHouse buyHouse = new BuyHouse();
//2. 代理对象
CProxy cglibProxy = new CProxy();
BuyHouse buyHouseCglibProxy = (BuyHouse) cglibProxy.getInstance(buyHouse);
//3. 代理方法调用
buyHouseCglibProxy.buy("房子");
}
}
// CGLIB工具类,将创建过程封装了
class CProxy{
//目标对象
private Object target;
public Object getInstance(final Object target) {
this.target = target;
//创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
Enhancer enhancer = new Enhancer();
//获取目标对象的类型 字节码文件
enhancer.setSuperclass(this.target.getClass());
//设置回调方法,在这方法里面调用目标对象的方法
enhancer.setCallback(new MethodInterceptor(){
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
//参数增强 对参数args进行增强
//方法增强 增加业务逻辑
System.out.println("买前准备");
Object result = proxy.invokeSuper(object, args);
// 返回值进行增强
return result;
}
});
//正式创建代理类
return enhancer.create();
}
}
/**
* 目标对象 没有接口的
*/
class BuyHouse {
public String buy(String name) {
System.out.println("buy " + name);
return "ok";
}
}
JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。