关于动态代理:浅谈JDK动态代理3转载

8次阅读

共计 5497 个字符,预计需要花费 14 分钟才能阅读完成。

相熟的陌生人

面试官如果问“请你谈谈你对 Spring 的了解”,预计很多人会脱口而出:IOC 和 AOP。IOC 大略是大家对 Spring 最间接的印象,就是个大容器,装了很多 bean,还会帮你做依赖注入。

IOC

然而对于 AOP,很多人其实没有太多概念,一时不晓得 Spring 哪里用了 AOP。如同事务用了切面,但具体又不理解。这样吧,我问你一个问题,我本人写了一个 UserController,以及 UserServiceImpl implements UserService,并且在 UserController 中注入 Service 层对象:

@Autowired
private UserService userService;

那么,这个 userService 肯定是咱们写的 UserServiceImpl 的实例吗?

如果你听不懂我要问什么,阐明你自身对 Spring 的理解还是太局限于 IOC。

实际上,Spring 依赖注入的对象并不一定是咱们本人写的类的实例,也可能是 userServiceImpl 的代理对象。上面别离演示这两种状况:

  • 注入 userServiceImpl 对象

注入的是 UserServiceImpl 类型

  • 注入 userServiceImpl 的代理对象(CGLib 动静代理)

注入的是 CGLib 动静代理生成的 userServiceImpl 的代理对象

为什么两次注入的对象不同?

因为第二次我给 UserServiceImpl 加了 @Transactional 注解。

此时 Spring 读取到这个注解,便晓得咱们要应用事务。而咱们编写的 UserService 类中并没有蕴含任何事务相干的代码。如果给你,你会怎么做?动静代理嘛!

然而要用动静代理实现事务管理,还须要本人编写一个告诉类,并把告诉对象传入代理对象,告诉负责事务的开启和提交,并在代理对象外部调用指标对象同名办法实现业务性能。

咱们能想到的计划,Spring 必定也晓得。同样地,Spring 为了实现事务,也编写了一个告诉类,TransactionManager。利用动静代理创立代理对象时,Spring 会把 transactionManager 织入代理对象,而后将代理对象注入到 UserController。

所以咱们在 UserController 中应用的 userService 其实是代理对象,而代理对象才反对事务。


山寨 AOP 事务需要剖析

理解了 Spring 事务的大抵流程后,咱们再来剖析一下本人如何编写一个山寨的 AOP 事务。

AOP 事务,有两个概念:AOP 和事务。

事务,大家曾经很相熟,这里次要讲讲什么是 AOP。AOP,它是 Aspect-Oriented Programming(面向切面编程) 的英文缩写。什么是面向切面编程?有时间接介绍一个货色是什么,可能比拟难。然而一说到它是干嘛的,大家就立刻心领神会了。

咱们的零碎中,经常存在穿插业务,比方事务、日志等。UserService 的 method1 要用到它,BrandService 的 method2 也要用到它。一个穿插业务就是要切入零碎的一个方面。具体用代码展现就是:

这个切面,能够是日志,也能够是事务

穿插业务的编程问题即为面向切面编程。AOP 的指标就是使穿插业务模块化。能够将切面代码移动到原始办法的四周:

原先不必 AOP 时,穿插业务间接写在 办法外部的前后 ,用了 AOP 穿插业务写在 办法调用前后。这与 AOP 的底层实现形式无关:动静代理其实就是代理对象调用指标对象的同名办法,并在调用前后加加强代码。不过这两种最终运行成果是一样的。

而所谓的模块化,我集体的了解是将切面代码做成一个可治理的状态。比方日志打印,不再是间接硬编码在办法中的零散语句,而是做成一个告诉类,通过告诉去执行切面代码。

所以,当初需要曾经很明确,咱们须要一个告诉类(TransactionManager)执行事务,一个代理工厂帮忙生成代理对象,而后利用动静代理将事务代码织入代理对象的各个办法中。

就好比上面三个 Service,原先是没有开启事务的:

咱们心愿最终达到的成果是,我加了个 @MyTransactional 后,代理工厂给我返回一个代理对象:

代理工厂应用动静代理,为每一个指标对象创立一个代理对象

细节剖析:

txManager 其实是在指标对象 test()办法的前后执行事务,而不是办法外部的前后

也就是说,代理对象办法 = 事务 + 指标对象办法。

另外,还有个辣手的问题:事务操作,必须应用同一个 Connection 对象。如何保障?第一次从数据源获取 Connection 对象并开启事务后,将它存入以后线程的 ThreadLocal 中,等到了 DAO 层,还是从 ThreadLocal 中取,这样就能保障开启事务和操作数据库应用的 Connection 对象是同一个。

开启事务后,Controller 并不是间接调用咱们本人写的 Service,而是 Spring 提供的代理对象

这就是事务的实现原理。


AOP 事务具体代码实现

ConnectionUtils 工具类

package com.demo.myaopframework.utils;

import org.apache.commons.dbcp.BasicDataSource;

import java.sql.Connection;

/**
 * 连贯的工具类,它用于从数据源中获取一个连贯,并且实现和线程的绑定
 */
public class ConnectionUtils {private ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

    private static BasicDataSource dataSource = new BasicDataSource();

    // 动态代码块, 设置连贯数据库的参数
    static{dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
    }


    /**
     * 获取以后线程上的连贯
     * @return
     */
    public Connection getThreadConnection() {
        try{
            //1. 先从 ThreadLocal 上获取
            Connection conn = tl.get();
            //2. 判断以后线程上是否有连贯
            if (conn == null) {
                //3. 从数据源中获取一个连贯,并且存入 ThreadLocal 中
                conn = dataSource.getConnection();
                tl.set(conn);
            }
            //4. 返回以后线程上的连贯
            return conn;
        }catch (Exception e){throw new RuntimeException(e);
        }
    }

    /**
     * 把连贯和线程解绑
     */
    public void removeConnection(){tl.remove();
    }
}

AOP 告诉(事务管理器)

package com.demo.myaopframework.utils;

/**
 * 和事务管理相干的工具类,它蕴含了,开启事务,提交事务,回滚事务和开释连贯
 */
public class TransactionManager {

    private ConnectionUtils connectionUtils;

    public void setConnectionUtils(ConnectionUtils connectionUtils) {this.connectionUtils = connectionUtils;}

    /**
     * 开启事务
     */
    public  void beginTransaction(){
        try {connectionUtils.getThreadConnection().setAutoCommit(false);
        }catch (Exception e){e.printStackTrace();
        }
    }

    /**
     * 提交事务
     */
    public  void commit(){
        try {connectionUtils.getThreadConnection().commit();}catch (Exception e){e.printStackTrace();
        }
    }

    /**
     * 回滚事务
     */
    public  void rollback(){
        try {connectionUtils.getThreadConnection().rollback();}catch (Exception e){e.printStackTrace();
        }
    }


    /**
     * 开释连贯
     */
    public  void release(){
        try {connectionUtils.getThreadConnection().close();// 还回连接池中
            connectionUtils.removeConnection();}catch (Exception e){e.printStackTrace();
        }
    }
}

自定义注解

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTransactional {}

Service

public interface UserService {void getUser();
}

 
public class UserServiceImpl implements UserService {
    @Override
    public void getUser() {System.out.println("service 执行...");
    }
}

实例工厂

public class BeanFactory {public Object getBean(String name) throws Exception {
        // 失去指标类的 Class 对象
        Class<?> clazz = Class.forName(name);
        // 失去指标对象
        Object bean = clazz.newInstance();
        // 失去指标类上的 @MyTransactional 注解
        MyTransactional myTransactional = clazz.getAnnotation(MyTransactional.class);
        // 如果打了 @MyTransactional 注解,返回代理对象,否则返回指标对象
        if (null != myTransactional) {ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
            TransactionManager txManager = new TransactionManager();
            txManager.setConnectionUtils(new ConnectionUtils());
            // 拆卸告诉和指标对象
            proxyFactoryBean.setTxManager(txManager);
            proxyFactoryBean.setTarget(bean);
            Object proxyBean = proxyFactoryBean.getProxy();
            // 返回代理对象
            return proxyBean;
        }
        // 返回指标对象
        return bean;
    }
}

代理工厂

public class ProxyFactoryBean {
    // 告诉
    private TransactionManager txManager;
    // 指标对象
    private Object target;

    public void setTxManager(TransactionManager txManager) {this.txManager = txManager;}

    public void setTarget(Object target) {this.target = target;}

    // 传入指标对象 target,为它拆卸好告诉,返回代理对象
    public Object getProxy() {
        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(),/*1. 类加载器 */
                target.getClass().getInterfaces(), /*2. 指标对象实现的接口 */
                new InvocationHandler() {/*3.InvocationHandler*/
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        try {
                            //1. 开启事务
                            txManager.beginTransaction();
                            //2. 执行操作
                            Object retVal = method.invoke(target, args);
                            //3. 提交事务
                            txManager.commit();
                            //4. 返回后果
                            return retVal;
                        } catch (Exception e) {
                            //5. 回滚事务
                            txManager.rollback();
                            throw new RuntimeException(e);
                        } finally {
                            //6. 开释连贯
                            txManager.release();}

                    }
                }
        );
        return proxy;
    }

}

代码构造

失去一般 UserService:

给 UserServiceImpl 增加 @MyTransactional 注解,失去代理对象:

正文完
 0