>>>> 😜😜😜 Making: 👉 github.com/black-ant
A. The preface
The last post talked about AOP initialization, how AOP creates AOP proxy classes through PostProcess,
2. AOP creates a starting point
AOP created
// In AbstractAutoProxyCreator # wrapIfNecessary, start the createProxy process to create a proxy class
createProxy(bean.getClass(), beanName, specificInterceptors, newSingletonTargetSource(bean))Copy the code
2.1 AbstractAutoProxyCreator Create a Proxy class
C- AbstractAutoProxyCreator
protected Object createProxy(Class<? > beanClass,@Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
// Create a ProxyFactory
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if(! proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else{ evaluateProxyInterfaces(beanClass, proxyFactory); }}// Build the notifier
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// Get the proxy object -> 2.3 Aop object creation details
// org.springframework.aop.framework.ProxyFactory
return proxyFactory.getProxy(getProxyClassLoader());
}
Copy the code
[PIC] : Contents of specificInterceptors object
[Pro] AutoProxyUtils function
C-autoproxyutils: Tool class m-shouldProxyTargetClass: determines whether a given bean should be proxied using the target class instead of the interface m-determinetargetClass: Determine the original target class of the specified bean, otherwise return to the general getType lookup m-ExposeTargetClass: Determine whether a given bean name indicates "original instance" based on ORIGINAL_INSTANCE_SUFFIXstatic void exposeTargetClass(
ConfigurableListableBeanFactory beanFactory, @NullableString beanName, Class<? > targetClass) {
if(beanName ! =null && beanFactory.containsBeanDefinition(beanName)) {
// ORIGINAL_TARGET_CLASS_ATTRIBUTE => org.springframework.aop.framework.autoproxy.AutoProxyUtils.originalTargetClassbeanFactory.getMergedBeanDefinition(beanName).setAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE, targetClass); }}// PS: the Attribute Attribute is set here, and we will see how this Attribute is used.
Copy the code
[Pro] ProxyFactory
This class provides a simple way to get and configure an INSTANCE of an AOP proxy in custom user code: Create a ProxyFactory Mc-proxyfactory (Object target) : create a ProxyFactory(Class<? >... ProxyFactory(Class<? > proxyInterface, Interceptor Interceptor) : a convenient method for creating a proxy for a single Interceptor Mc-proxyfactory (Class<? > proxyInterface, TargetSource TargetSource) : create a ProxyFactory for the specified TargetSource, and make the proxy implement the specified interface m-getProxy () : Create a new proxy based on the factory Settings, repeatedly calling m-getProxy (@Nullable ClassLoader classLoader) :
M- getProxy(Class<T> proxyInterface, Interceptor interceptor)
M- getProxy(Class<T> proxyInterface, TargetSource targetSource)
M- getProxy(TargetSource targetSource)
P- proxyInterface :
P- Interceptor :
P- TargetSource :
Copy the code
(Pro) Advisor
The basic interface that holds AOP Advice (actions to take at join points) and the filters that determine the applicability of Advice (such as pointcuts), the Advisor interface allows support for different types of Advice, such as Before Advice and After Advice c-Advisor: Notificator m-getAdvice () m-isperInstance ()When the Advisor was called >>>
Copy the code
2.2 buildAdvisors Creates notification objects
C- AbstractAutoProxyCreator
protected Advisor[] buildAdvisors(@Nullable String beanName, @Nullable Object[] specificInterceptors) {
// 2-2-1: resolves the specified interceptor name to an Advisor object
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++) {
// 2-2-2: resolves the specified interceptor name to the Advisor object
advisors[i] = this.advisorAdapterRegistry.wrap(allInterceptors.get(i));
}
return advisors;
}
// 2-2-1: resolves the specified interceptor name to an Advisor object
private Advisor[] resolveInterceptorNames() {
BeanFactory bf = this.beanFactory;
ConfigurableBeanFactory cbf = (bf instanceof ConfigurableBeanFactory ? (ConfigurableBeanFactory) bf : null);
List<Advisor> advisors = new ArrayList<>();
// Get the generic Interceptor object, which can be set by setInterceptorNames
for (String beanName : this.interceptorNames) {
if (cbf == null| |! cbf.isCurrentlyInCreation(beanName)) { Object next = bf.getBean(beanName); advisors.add(this.advisorAdapterRegistry.wrap(next)); }}return advisors.toArray(new Advisor[0]);
}
// 2-2-2: resolves the specified interceptor name to the Advisor object
C- DefaultAdvisorAdapterRegistry
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if(! (adviceObjectinstanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {
return newDefaultPointcutAdvisor(advice); }}throw new UnknownAdviceTypeException(advice);
}
Copy the code
3. Creation process of Aop proxy class
The previous section initiated the creation of a proxy with CreateProxy. This section describes the process of creating a ProxyFactory
Step 1: Obtain the main process of proxy class => ProxyFactory
// Class structure ===================
C- ProxyFactory
E- ProxyCreatorSupport
public Object getProxy(@Nullable ClassLoader classLoader) {
// createAopProxy() => org.springframework.aop.framework.ObjenesisCglibAopProxy
return createAopProxy().getProxy(classLoader);
}
// ProxyCreatorSupport is the parent class of ProxyFactory. CreateAopProxy calls this class method
protected final synchronized AopProxy createAopProxy(a) {
if (!this.active) {
// Activate the proxy configuration
activate();
}
// getAopProxyFactory() => org.springframework.aop.framework.DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}
Copy the code
Step 2: AOP agent factory selection
// Aop is based on Proxy, AopProxy interface, AopProxy create interface class AopProxyFactory, AopProxy
public interface AopProxyFactory {
/** * Create AopProxy */ for a given AOP configuration
AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException;
}
// The Aop proxy factory defaults to DefaultAopProxyFactory
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
Config.isoptimize () : Returns whether the agent should perform active optimization
/ / config. IsProxyTargetClass () : returns are direct agent for the target class and any interface
/ / hasNoUserSuppliedProxyInterfaces (config) : to determine whether AdvisedSupport provided only specifies the SpringProxy interface (or no specified proxy interface)
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 newJdkDynamicAopProxy(config); }}// PS: Spring classes use JdkDynamicAopProxy by default. Custom AOP classes usually use CglibAopProxyYou can configure it in the following ways:// Option 1: You can switch configurations when building beans. For example:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ExecutableValidator.class)
@ConditionalOnResource(resources = "classpath:META-INF/services/javax.validation.spi.ValidationProvider")
@Import(PrimaryDefaultValidatorPostProcessor.class)
public class ValidationAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public static MethodValidationPostProcessor methodValidationPostProcessor(Environment environment,
@Lazy Validator validator) {
MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
// Set proxy target object
boolean proxyTargetClass = environment.getProperty("spring.aop.proxy-target-class", Boolean.class, true);
processor.setProxyTargetClass(proxyTargetClass);
processor.setValidator(validator);
returnprocessor; }}// Method 2: configure the AOP proxy mode
1.Enable EnableAspectJAutoProxy2.Through the property spring.aop.proxy-target-classconfigureCopy the code
Step 3-1: CglibAopProxy Create a proxy class
C- CglibAopProxy
public Object getProxy(@Nullable ClassLoader classLoader) {
try{ Class<? > rootClass =this.advised.getTargetClass(); Class<? > proxySuperClass = rootClass;// String CGLIB_CLASS_SEPARATOR = "$$";
/ / contains $$
if(rootClass.getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)) { proxySuperClass = rootClass.getSuperclass(); Class<? >[] additionalInterfaces = rootClass.getInterfaces();for(Class<? > additionalInterface : additionalInterfaces) {this.advised.addInterface(additionalInterface); }}// Check whether the supplied Class has been validated, and if not, verify it
validateClassIfNecessary(proxySuperClass, classLoader);
// Configure CGLIB enhancement -> RPO31001
Enhancer enhancer = createEnhancer();
if(classLoader ! =null) {
enhancer.setClassLoader(classLoader);
if (classLoader instanceof SmartClassLoader &&
((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
enhancer.setUseCache(false);
}
}
enhancer.setSuperclass(proxySuperClass);
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(newClassLoaderAwareGeneratorStrategy(classLoader)); Callback[] callbacks = getCallbacks(rootClass); Class<? >[] types =newClass<? >[callbacks.length];for (int x = 0; x < types.length; x++) {
types[x] = callbacks[x].getClass();
}
// fixedInterceptorMap only populated at this point, after getCallbacks call above
enhancer.setCallbackFilter(new ProxyCallbackFilter(
this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
enhancer.setCallbackTypes(types);
// Generate the proxy class and create the proxy instance
return createProxyClassAndInstance(enhancer, callbacks);
}
catch (CodeGenerationException | IllegalArgumentException ex) {
throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
": Common causes of this problem include using a final class or a non-visible class",
ex);
}
catch (Throwable ex) {
// TargetSource.getTarget() failed
throw new AopConfigException("Unexpected AOP exception", ex); }}protected Object createProxyClassAndInstance(Enhancer enhancer, Callback[] callbacks) {
enhancer.setInterceptDuringConstruction(false);
enhancer.setCallbacks(callbacks);
// Each is created by whether there is a construct parameter
return (this.constructorArgs ! =null && this.constructorArgTypes ! =null ?
enhancer.create(this.constructorArgTypes, this.constructorArgs) :
enhancer.create());
}
// RPO31001 adds: Enhancer roleThe common way to Proxy is through a Proxy class, and Enhancer is also a method Proxy class. Proxy is an interface based Proxy, and Enhancer is an inheritance based ProxyCopy the code
Step 3-2 : JdkDynamicAopProxy
// JdkDynamicAopProxy builds the proxy class
public Object getProxy(@Nullable ClassLoader classLoader) { Class<? >[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
// Create a proxy class
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
Copy the code
AopProxy Proxy system
Proxy classes in Spring usually have2CglibAopProxy/JdkDynamicAopProxy// [Pro] : How to switch AopProxy type
Copy the code
4. Go deep
4.1 Use of the ORIGINAL_TARGET_CLASS_ATTRIBUTE attribute
// Step 1 : AbstractApplicationContext # refresh
public void refresh(a) throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
try {
/ /...
// Instantiate all remaining (non-lazy-init) singletons
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
/ /...}}// PS: You can see that in the penultimate step of the main process,
/ / EventListenerMethodProcessor: method of marking the @ EventListener parsing, and then converted to a ApplicationListener
// Step 2: C- EventListenerMethodProcessor # afterSingletonsInstantiated
public void afterSingletonsInstantiated(a) {
ConfigurableListableBeanFactory beanFactory = this.beanFactory;
String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
for (String beanName : beanNames) {
if(! ScopedProxyUtils.isScopedTarget(beanName)) { Class<? > type =null;
try {
// Determines the original target class of the specified bean
// Step 2-1: Obtain originalTargetClass
// beanName -> org.springframework.context.annotation.internalConfigurationAnnotationProcessor
// type -> org.springframework.context.annotation.ConfigurationClassPostProcessor
type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
}
catch (Throwable ex) {
/ /...
}
if(type ! =null) {
if (ScopedObject.class.isAssignableFrom(type)) {
try{ Class<? > targetClass = AutoProxyUtils.determineTargetClass( beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));if(targetClass ! =null) { type = targetClass; }}catch (Throwable ex) {
/ /...}}try {
// Step 2-3: Obtain originalTargetClass
processBean(beanName, type);
}
catch (Throwable ex) {
/ /...
}
}
}
}
}
// Step 2-1: Get originalTargetClass from BeanDefinition
String ORIGINAL_TARGET_CLASS_ATTRIBUTE = Conventions.getQualifiedAttributeName(AutoProxyUtils.class, "originalTargetClass"); BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName); Class<? > targetClass = (Class<? >) bd.getAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE);// Step 2-2: Look for the original target class. You can see that the class to be queried usually starts with internalXXX and is created in beanDefinitionNames
public staticClass<? > determineTargetClass( ConfigurableListableBeanFactory beanFactory,@Nullable String beanName) {
if (beanName == null) {
return null;
}
if(beanFactory.containsBeanDefinition(beanName)) { BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName); Class<? > targetClass = (Class<? >) bd.getAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE);if(targetClass ! =null) {
returntargetClass; }}return beanFactory.getType(beanName);
}
// Step 2-3: This method is omitted, which is mainly for the EventListener annotation processing, and has nothing to do with the main process
private void processBean(final String beanName, finalClass<? > targetType)
Copy the code
4.2 AOP Cglib configuration process
Usually the basic AOP proxy is through
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration$AspectJAutoProxyingConfiguration$CglibAutoProxyConfiguration
public void registerBeanDefinitions( AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);
// h
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
//
if(enableAspectJAutoProxy ! =null) {
if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (enableAspectJAutoProxy.getBoolean("exposeProxy")) { AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry); }}}public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
// AUTO_PROXY_CREATOR_BEAN_NAME => org.springframework.aop.config.internalAutoProxyCreator
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE); }}Copy the code
Supplement 1: EnableAspectJAutoProxy
public @interface EnableAspectJAutoProxy {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}.
*/
boolean proxyTargetClass(a) default false;
/**
* Indicate that the proxy should be exposed by the AOP framework as a {@code ThreadLocal}
* for retrieval via the {@link org.springframework.aop.framework.AopContext} class.
* Off by default, i.e. no guarantees that {@code AopContext} access will work.
* @since4.3.1 * /
boolean exposeProxy(a) default false;
}
Copy the code
Supplement 2: AopAutoConfiguration Automatic configuration class
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Advice.class)
static class AspectJAutoProxyingConfiguration {
@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
static class JdkDynamicAutoProxyConfiguration {}@Configuration(proxyBeanMethods = false)
@EnableAspectJAutoProxy(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
static class CglibAutoProxyConfiguration {}}@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.aspectj.weaver.Advice")
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
static class ClassProxyingConfiguration {
ClassProxyingConfiguration(BeanFactory beanFactory) {
if (beanFactory instanceofBeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); }}}}Copy the code
Add 3: org. Springframework. Aop. Config. InternalAutoProxyCreator role
C- AopConfigUtils # String AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator"? - The bean name of the internally managed automatic proxy creatorCopy the code
conclusion
To be fair, this article is not well written, many places are not clear now, limited energy can not be detailed and in-depth, generally speaking, it is a semi-finished product, later time is sufficient, let’s have a deeper look
Core concepts:
- AbstractAutoProxyCreator # createProxy Initiates the creation of a proxy class
- AutoProxyUtils is a utility class for some common action handling of the original class and the proxy
- Use AopProxyFactory to create proxy classes. There are two types: ObjenesisCglibAopProxy and JdkDynamicAopProxy