浅谈JDK动态代理<3转载>

熟悉的陌生人

面试官若是问“请你谈谈你对Spring的理解”,估计不少人会脱口而出:IOC和AOP。IOC大概是你们对Spring最直接的印象,就是个大容器,装了不少bean,还会帮你作依赖注入。java

IOCmysql

可是对于AOP,不少人其实没有太多概念,一时不知道Spring哪里用了AOP。好像事务用了切面,但具体又不了解。这样吧,我问你一个问题,我本身写了一个UserController,以及UserServiceImpl implements UserService,而且在UserController中注入Service层对象:面试

@Autowired
private UserService userService;

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

若是你听不懂我要问什么,说明你自己对Spring的了解仍是太局限于IOC。数据库

实际上,Spring依赖注入的对象并不必定是咱们本身写的类的实例,也多是userServiceImpl的代理对象。下面分别演示这两种状况:apache

  • 注入userServiceImpl对象

注入的是UserServiceImpl类型编程

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

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

为何两次注入的对象不一样?模块化

由于第二次我给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注解,获得代理对象:

相关文章
相关标签/搜索