相熟的陌生人
面试官如果问“请你谈谈你对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注解,失去代理对象:
发表回复