背景
今天看到项目中一段代码
@Transactional(propagation = Propagation.REQUIRES_NEW) private TmShowConfig initTmShowConfig(String userId, String configType)
有没有感觉到哪里有问题?
分析
我们在使用Spring做aop的时候 无非两种代理模式
基于jdk的proxy 动态代理小结之proxy
我们来看Spring按照什么策略生成代理
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class<?> targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) { return new JdkDynamicAopProxy(config); } return new ObjenesisCglibAopProxy(config); } else { return new JdkDynamicAopProxy(config); } } }
很明显默认情况下均使用JdkDynamicAopProxy 当ProxyTargetClass开启是 如果对象不是借口的话将会返回ObjenesisCglibAopProxy 否则仍然返回JdkDynamicAopProxy
CGlib 我们都了解了 但是ObjenesisCglibAopProxy 是个啥呢? 在Spring4之后默认采用了Objenesis这样的实现方式。
Java already supports this dynamic instantiation of classes using Class.newInstance()
. However, this only works if the class has an appropriate constructor. There are many times when a class cannot be instantiated this way, such as when the class contains:
- Constructors that require arguments.
- Constructors that have side effects.
- Constructors that throw exceptions.
As a result, it is common to see restrictions in libraries stating that classes must require a default constructor. Objenesis aims to overcome these restrictions by bypassing the constructor on object instantiation.
这个对我们的影响是啥呢?从此cglib的代理类不再需要一定提供无参构造函数了!!!【不过思考final域怎么办】
通常我们提到aop免不了提到的是如下几个关键词
- advisor
- pointcut
- introduction
- advice
具体继承图如下

简单解释一下
- advisor称之为切面 该接口中包含了advice
- pointcut 是一种切面通常描述了那些被增强的方法
- introduction称之为引入 也是一种切面 通常会给实现类增加额外的接口方法
- advice 称之为增强 spring直接使用了aspectj的定义
我们最常使用的是pointcut 一般用来拦截某些指定的方法实现切面编程!
那么就可以提到本次关于事务的切面是如何实现的!
事务的切面定义如下
public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor { private TransactionInterceptor transactionInterceptor; private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() { @Override protected TransactionAttributeSource getTransactionAttributeSource() { return (transactionInterceptor != null ? transactionInterceptor.getTransactionAttributeSource() : null); } }; /** * Create a new TransactionAttributeSourceAdvisor. */ public TransactionAttributeSourceAdvisor() { } /** * Create a new TransactionAttributeSourceAdvisor. * @param interceptor the transaction interceptor to use for this advisor */ public TransactionAttributeSourceAdvisor(TransactionInterceptor interceptor) { setTransactionInterceptor(interceptor); } /** * Set the transaction interceptor to use for this advisor. */ public void setTransactionInterceptor(TransactionInterceptor interceptor) { this.transactionInterceptor = interceptor; } /** * Set the {@link ClassFilter} to use for this pointcut. * Default is {@link ClassFilter#TRUE}. */ public void setClassFilter(ClassFilter classFilter) { this.pointcut.setClassFilter(classFilter); } @Override public Advice getAdvice() { return this.transactionInterceptor; } @Override public Pointcut getPointcut() { return this.pointcut; } }
查看其对应的pointcut定义如下
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { @Override public boolean matches(Method method, Class<?> targetClass) { if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) { return false; } TransactionAttributeSource tas = getTransactionAttributeSource(); return (tas == null || tas.getTransactionAttribute(method, targetClass) != null); }
很明显当实现TransactionalProxy接口的将不会开启事务【需要手动维护】
我们知道当定义spring事务的时候有个属性为proxy-target-class【默认为false则使用jdk代理 设置为true使用cglib代理】