代理模式
静态代理
场景:
服务层有增删查改功能, 现在需要对增删改添加事务的支持.
如果在基础的代码上修改的话会很麻烦, 所以使用代理的模式
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...");
- }
- }
动态代理的好处
静态代理有的它都有, 静态代理没有的, 它也有!
可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
公共的业务由代理来完成 . 实现了业务的分工 ,
公共业务发生扩展时变得更加集中和方便 .
一个动态代理 , 一般代理某一类业务
一个动态代理可以代理多个类, 代理的是接口!
来源: http://www.bubuko.com/infodetail-3327545.html