1. La différence et le lien entre AOP et transaction
La classe d'assemblage automatique qui introduit AOP est AopAutoConfiguration
, et la classe d'assemblage automatique qui introduit les transactions est TransactionAutoConfiguration
.
La fonctionnalité AOP est spring-boot-starter-aop
fournie par les dépendances. La fonctionnalité de transaction est spring-tx
fournie par les dépendances.
Les proxy beans impliqués dans Aop & transaction incluent :
- Le bean proxy impliqué dans Aop implique principalement la classe spécifiée par pointcut.
- Les beans proxy impliqués dans la transaction impliquent principalement la classe avec @transaction et la classe avec la méthode avec cette annotation.
1.1、AopAutoConfiguration
Les types EnableAspectJAutoProxy
sont introduits par des annotations . Le but d'AspectJAutoProxyRegistrar est d'introduire les post-processeurs liés à AOP .ImportBeanDefinitionRegistrar
AspectJAutoProxyRegistrar
AnnotationAwareAspectJAutoProxyCreator
1.2、TransactionAutoConfiguration
Les types EnableTransactionManagement
sont introduits par des annotations . Le but de TransactionManagementConfigurationSelector est d'introduire l'un des post-processeurs liés aux transactions , parmi lesquels le but d'AutoProxyRegistrar est d'introduire , et ProxyTransactionManagementConfiguration est d'introduire le point de connexion && lié aux transactions TransactionAttributeSourcePointcut.ImportSelector
TransactionManagementConfigurationSelector
AutoProxyRegistrar
ProxyTransactionManagementConfiguration
InfrastructureAdvisorAutoProxyCreator
环绕通知TransactionInterceptor
切面BeanFactoryTransactionAttributeSourceAdvisor
Le bean dans l'aspect lié aux transactions BeanFactoryTransactionAttributeSourceAdvisor dans son conteneur IOC est org.springframework.transaction.config.internalTransactionAdvisor.
1.3、AopConfigUtils
La méthode principale de la classe consiste à initialiser la sous-classe de la classe abstraite AbstractAutoProxyCreator. Ses sous-classes sont toutes importées indirectement via la classe d'assemblage automatique. Et ces post-processeurs sont déclenchés lorsque les BeanDefinitions correspondantes sont complétées après le chargement de toutes les classes d'assemblage automatiques .
public abstract class AopConfigUtils {
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
static {
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
}
Si aop & transactions existent dans le projet en même temps, AspectJAutoProxyRegistrar et AutoProxyRegistrar initialisent respectivement les post-processeurs correspondants via AopConfigUtils. Cependant, étant donné que le beanName des deux post-processeurs dans le conteneur IOC est le même AUTO_PROXY_CREATOR_BEAN_NAME
, registerOrEscalateApcAsRequired
on sait grâce à la méthode ci-dessus que seuls les post-processeurs liés à AOP existent dans ce cas.
2、AbstractAutoProxyCreator
public abstract class AbstractAutoProxyCreator implements SmartInstantiationAwareBeanPostProcessor{
private BeanFactory beanFactory;
private final Map<Object, Boolean> advisedBeans = new ConcurrentHashMap<>(256);
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
Object cacheKey = getCacheKey(beanClass, beanName);
if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
if (this.advisedBeans.containsKey(cacheKey)) {
return null;
}
if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return null;
}
}
TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
...
return null;
}
...
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
...
// Create proxy if we have advice.
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);//#1
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// Handle prototypes correctly...
Advisor[] commonInterceptors = resolveInterceptorNames();
List<Object> allInterceptors = new ArrayList<>();
if (specificInterceptors != null) {
allInterceptors.addAll(Arrays.asList(specificInterceptors));
if (commonInterceptors.length > 0) {
if (this.applyCommonInterceptorsFirst) {
allInterceptors.addAll(0, Arrays.asList(commonInterceptors));
}
else {
allInterceptors.addAll(Arrays.asList(commonInterceptors));
}
}
}
Advisor[] advisors = new Advisor[allInterceptors.size()];
for (int i = 0; i < allInterceptors.size(); i++) {
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
}
La propriété advisorBeans du type de collection Map, son élément est un bean proxy inutile.
isInfrastructureClass : indique s'il s'agit d'une classe d'infrastructure liée à aop. infrastructureClass inclut Advice, Pointcut, Advisor, AopInfrastructureBean et @Aspect fournis par AnnotationAwareAspectJAutoProxyCreator. Aucune de ces classes d'infrastructure ne nécessite de traitement proxy.
- Etape 1 : AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean, pour obtenir différents conseils de la classe d'aspect Advisor correspondant au bean courant et le type Interceptor correspondant dans la classe d'aspect.
2.1、AbstractAdvisorAutoProxyCreator
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {
private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper;
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName,TargetSource targetSource) {
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
List<Advisor> candidateAdvisors = findCandidateAdvisors();//#1
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);//#2
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
protected List<Advisor> findCandidateAdvisors() {
//#3
return this.advisorRetrievalHelper.findAdvisorBeans();
}
protected List<Advisor> findAdvisorsThatCanApply(
List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
ProxyCreationContext.setCurrentProxiedBeanName(beanName);
try {
return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
}
finally {
ProxyCreationContext.setCurrentProxiedBeanName(null);
}
}
private class BeanFactoryAdvisorRetrievalHelperAdapter extends BeanFactoryAdvisorRetrievalHelper {
public BeanFactoryAdvisorRetrievalHelperAdapter(ConfigurableListableBeanFactory beanFactory) {
super(beanFactory);
}
@Override
protected boolean isEligibleBean(String beanName) {
return AbstractAdvisorAutoProxyCreator.this.isEligibleAdvisorBean(beanName);
}
}
}
- Étape 1 : Obtenir les classes d'aspects des candidats
- S'il y a une transaction, elle obtient principalement
org.springframework.transaction.config.internalTransactionAdvisor
la classe d'aspect candidat Advisor dont le beanName estBeanFactoryTransactionAttributeSourceAdvisor
. Le candidat Advisor n'est pas obtenu à l'aide d'InfrastructureAdvisorAutoProxyCreator. - S'il y a aop, il est fourni par sa sous-classe AnnotationAwareAspectJAutoProxyCreator, comme suit :
protected List<Advisor> findCandidateAdvisors() {
、
List<Advisor> advisors = super.findCandidateAdvisors();//AbstractAdvisorAutoProxyCreator#findCandidateAdvisors
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
Comme indiqué ci-dessus, AnnotationAwareAspectJAutoProxyCreator essaie d'obtenir le conseiller de la classe d'aspect sélectionnée et le conseiller du type AspectJ. Si transaction & Aop existent dans l'application en même temps, les conseillers correspondant aux deux sont fournis par AnnotationAwareAspectJAutoProxyCreator [Parce que le post-processeur de InfrastructureAdvisorAutoProxyCreator et AnnotationAwareAspectJAutoProxyCreator ont le même beanName , seul ce dernier existe dans le conteneur IOC] org.springframework.aop.config.internalAutoProxyCreator
.
- Étape 2 : Dans le processus d'initialisation du bean dans l'application, tous les conseillers de classe d'aspect [transaction et Aop] sont d'abord initialisés, puis à travers cette étape, les conseillers candidats dont le bean actuel a réellement besoin sont déterminés. Si le bean actuel n'a que des transactions, filtrez la classe d'aspect liée à l'AOP Advisor...etc.
BeanFactoryAdvisorRetrievalHelper
#findAdvisorBeans, la logique de base obtient principalement la classe d'aspect candidate Advisor, telle que BeanFactoryTransactionAttributeSourceAdvisor, par exemple comme suit :
public class BeanFactoryAdvisorRetrievalHelper {
public List<Advisor> findAdvisorBeans() {
String[] advisorNames = this.cachedAdvisorBeanNames;
if (advisorNames == null) {
// 从IOC容器DefaultListableBeanFactory中获取Advisor相关的beanName
//例如事务相关的org.springframework.transaction.config.internalTransactionAdvisor
advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Advisor.class, true, false);
this.cachedAdvisorBeanNames = advisorNames;
}
if (advisorNames.length == 0) {
return new ArrayList<>();
}
List<Advisor> advisors = new ArrayList<>();
for (String name : advisorNames) {
if (isEligibleBean(name)) {
if (this.beanFactory.isCurrentlyInCreation(name)) {
}else {
advisors.add(this.beanFactory.getBean(name, Advisor.class));
}
}
}
return advisors;
}
}
isEligibleBean : renvoie vrai par défaut. Le post-processeur InfrastructureAdvisorAutoProxyCreator remplace cette méthode.