spring学习9-代理模式

代理模式

静态代理

场景:

服务层有增删查改功能,现在需要对增删改添加事务的支持。

如果在基础的代码上修改的话会很麻烦,所以使用代理的模式

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:调用处理程序

spring学习9-代理模式_第1张图片

Object invoke(Object proxy, 方法 method, Object[] args);
//参数 
//proxy - 调用该方法的代理实例 
//method -所述方法对应于调用代理实例上的接口方法的实例。 方法对象的声明类将是该方法声明的接口,它可以是代理类继承该方法的代理接口的超级接口。 
//args -包含的方法调用传递代理实例的参数值的对象的阵列,或null如果接口方法没有参数。 原始类型的参数包含在适当的原始包装器类的实例中,例如java.lang.Integer或java.lang.Boolean 。 

Proxy : 代理

spring学习9-代理模式_第2张图片

spring学习9-代理模式_第3张图片

//生成代理类
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...");
    }
}

动态代理的好处

静态代理有的它都有,静态代理没有的,它也有!

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
  • 公共的业务由代理来完成 . 实现了业务的分工 ,
  • 公共业务发生扩展时变得更加集中和方便 .
  • 一个动态代理 , 一般代理某一类业务
  • 一个动态代理可以代理多个类,代理的是接口!

你可能感兴趣的:(spring学习9-代理模式)