代理模式
静态代理
场景:
服务层有增删查改功能,现在需要对增删改添加事务的支持。
如果在基础的代码上修改的话会很麻烦,所以使用代理的模式
1.抽象角色
创建一个抽象角色,比如咋们平时做的用户业务,抽象起来就是增删改查!
//抽象角色:增删改查业务
public interface UserService {
void add();
void delete();
void update();
void query();
}
2.真实对象
我们需要一个真实对象来模拟完成这些增删改查操作
//真实对象,完成增删改查操作的人
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加一个用户");
}
@Override
public void delete() {
System.out.println("删除一个用户");
}
@Override
public void update() {
System.out.println("更新一个用户");
}
@Override
public void query() {
System.out.println("查找一个用户");
}
}
3.模拟事务
public class MyTransaction {
public void starTranSaction(){
System.out.println("开启事务...");
}
public void closeTranSaction(){
System.out.println("关闭事务...");
}
}
4.代理角色
设置一个代理类来模拟处理事务
/代理角色,在这里面增加事务的支持
public class UserServiceProxy implements UserService {
private MyTransaction transaction = new MyTransaction();
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
@Override
public void add() {
transaction.starTranSaction();
userService.add();
transaction.closeTranSaction();
}
@Override
public void delete() {
transaction.starTranSaction();
userService.delete();
transaction.closeTranSaction();
}
@Override
public void update() {
transaction.starTranSaction();
userService.update();
transaction.closeTranSaction();
}
@Override
public void query() {
userService.query();
}
}
5.测试
@Test
public void test1() {
UserServiceImpl userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(userService);
proxy.query();
proxy.add();
proxy.delete();
proxy.update();
}
6.结果
可以看到,查找的时候没有事务,其它的都添加了事务的支持
查找一个用户
开启事务...
增加一个用户
关闭事务...
开启事务...
删除一个用户
关闭事务...
开启事务...
更新一个用户
关闭事务...
代理模式的优缺点:
优点:
- 可以使真实角色的操作更加纯粹,不用去关心一些公共的业务
- 公共的业务交给了代理角色,实现业务分工
- 公共业务发生扩展的时候,方便集中管理
缺点:
- 一个真实角色就会产生一个代理角色,代码量翻倍,开发效率变低
这时候就可以考虑动态代理了
动态代理
- 动态代理的角色和静态代理的一样 .
- 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
- 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
- 基于接口的动态代理----JDK动态代理
- 基于类的动态代理--cglib
- 现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist
- 我们这里使用JDK的原生代码来实现,其余的道理都是一样的!
JDK的动态代理需要了解两个类
核心 : InvocationHandler 和 Proxy , 打开JDK帮助文档看看
InvocationHandler:调用处理程序
Object invoke(Object proxy, 方法 method, Object[] args);
//参数
//proxy - 调用该方法的代理实例
//method -所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。
//args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。
Proxy : 代理
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
rent.getClass().getInterfaces(),this);
}
代码实现
动态代理处理程序
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//这是处理程序,不是代理类,可以通过这个处理程序生成一个带类
public class UserServiceInvocationHandler implements InvocationHandler {
private MyTransaction transaction = new MyTransaction();
private UserService userService;//被代理的接口
public void setUserService(UserService userService) {
this.userService = userService;
}
//生成代理类,重点是第二个参数,获取要代理的抽象角色!
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
userService.getClass().getInterfaces(),this);
}
// 处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("query")){
Object result = method.invoke(userService,args);
return result;
}else {
transaction.starTranSaction();
Object result = method.invoke(userService,args);//核心:本质利用反射实现!
transaction.closeTranSaction();
return result;
}
}
}
测试
//动态代理
@Test
public void test2() {
UserServiceImpl userService = new UserServiceImpl();//真实角色
UserServiceInvocationHandler pih = new UserServiceInvocationHandler();//处理程序
pih.setUserService(userService); //设置代理的对象
UserService proxy = (UserService) pih.getProxy(); //动态生成对应的代理类!
proxy.query();
proxy.add();
proxy.delete();
proxy.update();
}
结果
查找一个用户
开启事务...
增加一个用户
关闭事务...
开启事务...
删除一个用户
关闭事务...
开启事务...
更新一个用户
关闭事务...
核心:一个动态代理 , 一般代理某一类业务 , 一个动态代理可以代理多个类,代理的是接口!、
动态代理程序模板
我们也可以编写一个通用的动态代理实现的类!所有的代理对象设置为Object即可!
//动态代理处理程序
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;//代理的接口
public void setTarget(Object target) {
this.target = target;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
doSomething();//在真实对象的方法执行之前执行额外业务
Object result = method.invoke(target,args);//通过反射生成代理对象
return result;
}
//额外的业务
private void doSomething(){
System.out.println("run...");
}
}
动态代理的好处
静态代理有的它都有,静态代理没有的,它也有!
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
- 公共的业务由代理来完成 . 实现了业务的分工 ,
- 公共业务发生扩展时变得更加集中和方便 .
- 一个动态代理 , 一般代理某一类业务
- 一个动态代理可以代理多个类,代理的是接口!