一、代理模式简介
代理:例如A没空,叫B去帮他完成某个事,B就是A的代理人,A就是被代理人
代理模式的作用:在不修改原代码的情况下增强一个类的功能
被代理类A:需要增强功能类 委托类
代理类B:增强代码编写的地方 A类的代理类
**
二、静态代理
代理类B需要程序员手动的编写,代码需要写死,静态
1、需要一个公共的接口 BankService
2、被代理类必须实现该接口 BankServiceImpl
3、需要编写代理类,代理类也必须实现公共接口,代理类中需要有一个被代理类的属性
代码:
//公共的接口
interface BankService{
public void transfer();
}
//被代理类:添加事务处理的代码、功能
class BankServiceImpl implements BankService{
@Override
public void transfer() {
System.out.println("加钱sql");
System.out.println("减钱sql");
}
}
//代理类
class BankServiceProxy implements BankService{
//指向被代理类对象
public BankService bankService;
public BankServiceProxy(BankService bankService) {
super();
this.bankService = bankService;
}
@Override
public void transfer() {
System.out.println("====开启事务====");
//原有的功能
bankService.transfer();
System.out.println("====提交/回滚====");
}
}
public class TestServlet {
private BankService bankService = new BankServiceProxy(new BankServiceImpl());
//处理转账请求
@Test
public void transfer() {
bankService.transfer();
}
}
执行效果:
====开启事务====
加钱sql
减钱sql
====提交/回滚====
缺点:维护、扩展比较麻烦
三、动态代理
代理类B不需要程序员手动的编写,是由程序自动生成的,动态
动态代理的扩展性要比静态代理强一些
3.1 JDK动态代理
JDK自带的代理方式
1、需要一个公共的接口
2、被代理类需要实现接口
3、创建一个工厂类,需要提供一个方法用来获取被代理类对象,工厂必须拥有一个指向代理对象的属性
代码:
//公共的接口
interface BankService {
public void transfer();
}
//被代理类:添加事务处理的代码、功能
class BankServiceImpl implements BankService {
@Override
public void transfer() {
System.out.println("加钱sql");
System.out.println("减钱sql");
}
}
//代理工厂
class JdkProxyFactory {
// 指向被代理类对象
private Object target;
public JdkProxyFactory(Object target) {
super();
this.target = target;
}
// 获取代理类对象的方法
public Object getProxyInstance() {
// 类加载器
ClassLoader classLoader = this.getClass().getClassLoader();
// 被代理类实现的所有接口
Class<?>[] interfaces = target.getClass().getInterfaces();
// invocationHandler处理器
InvocationHandler handler = new InvocationHandler() {
// 参数1:JDK生成的代理类对象
// 参数2:需要调用的方法
// 参数3:调用该方法时的参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("====开启事务====");
//
Object result = method.invoke(target, args);
//
System.out.println("====提交/回滚====");
// 返回执行结果
return result;
}
};
// 参数1:类加载器
// 参数2:被代理类实现的所有接口
// 参数3:invocationHandler处理器
return Proxy.newProxyInstance(classLoader, interfaces, handler);
}
}
public class Jdk {
// 一步到位
// BankService bankService =
// (BankService)new JdkProxyFactory(new BankServiceImpl()).getProxyInstance();
@Test
public void test() {
// 创建工厂
JdkProxyFactory factory = new JdkProxyFactory(new BankServiceImpl());
// 获取代理类对象
Object proxy = factory.getProxyInstance();
// com.woniuxy.dynamic.BankServiceImpl@2b05039f 重写了toString
System.out.println(proxy);
// class com.woniuxy.dynamic.$Proxy4 代理类,是BankService的子类
System.out.println(proxy.getClass());
// instanceof 判断某个对象是否是指定类型及其子类的对象
if (proxy instanceof BankService) {
BankService bankService = (BankService) proxy;
// 调用业务
// 调用的是代理类对象的方法,只要调用这些方法就会自动调用handler中的invoke方法
bankService.transfer();
}
}
}
JDK代理实现的逻辑:
在创建代理类对象时给Proxy.newProxyInstance(classLoader,interfaces,handler);传递了三个参数,其中第二参数是被代理类实现的所有接口,所以JDK代理在生成代理类时实现这些接口,所以生成的代理类就是接口(BankService)的子类,所以生成的代理类对象也就是BankService类型的对象,之后在调用代理类对象相关方法时(transfer),会自动执行handler中的invoke方法,然后传入三个参数:代理类对象、调用的方法及方法的参数,然后在invoke方法中通过Object result = method.invoke(target, args);执行被代理类对象的方法(原有功能 SQL)然后返回结果。
接口与类、类与类之间的关系:
BankService 与 代理类($Proxy4) :父子关系,BankService 是父,$Proxy0是子
BankServiceImpl 与 代理类($Proxy0) :同胞、兄弟
缺点:被代理类必须实现接口
3.2 Cglib代理
第三方的代理方式,CGLIB代理也叫做子类代理,生成的代理类是被代理类的子类
1、没有实现任何接口的被代理类
2、创建一个工厂类,需要包含一个指向被代理类对象的属性,提供一个生成代理类对象的方法
导包:
asm-3.3.1.jar
cglib-2.2.2.jar
代码:
//被代理类
class CBankServiceImpl {
public void transfer() {
System.out.println("加钱sql");
System.out.println("减钱sql");
}
}
//工厂类
class CglibProxyFactory {
// 指向被代理类的对象
private Object target;
public CglibProxyFactory(Object target) {
super();
this.target = target;
}
// 获取代理类对象
public Object getProxyInstance() {
// 创建工具类对象:生成代理类对象
Enhancer enhancer = new Enhancer();
// 指定代理类的父类(被代理类)
enhancer.setSuperclass(target.getClass());
// 设置处理器
enhancer.setCallback(new MethodInterceptor() {
// 参数1:生成的代理类对象
// 参数2:需要调用的方法
// 参数3:调用该方法时的参数
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("====开启事务====");
// 执行原功能
Object result = method.invoke(target, args);
System.out.println("====提交/回滚====");
return result;
}
});
//生成代理类对象
return enhancer.create();
}
}
public class Cglib {
// 一步到位
// CBankServiceImpl cBankServiceImpl =
// (CBankServiceImpl) new CglibProxyFactory(new CBankServiceImpl()).getProxyInstance();
@Test
public void test() {
CglibProxyFactory factory = new CglibProxyFactory(new CBankServiceImpl());
//
Object proxy = factory.getProxyInstance();
// class com.woniuxy.staticproxy.CBankServiceImpl$$EnhancerByCGLIB$$271ac22b
System.out.println(proxy.getClass());
//
if(proxy instanceof CBankServiceImpl) {
CBankServiceImpl impl = (CBankServiceImpl)proxy;
impl.transfer();
}
}
}
缺点:被代理类不能是final修饰的
注意:生成的代理类是被代理类的子类