前面我們已經探討過基於spring的動態aop處理 spring動態aop處理 spring同時也遵循了aop的標準,提供了靜態aop的處理方式。
spring的配置增加如下配置開啓靜態aop:
<context:load-time-weaver/>
可以看到,這裏對應的schema是context
,我們在spring-context
模塊下META-IUNF/spring.handlers
中發現內容如下:
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
其中context
對應處理類爲:org.springframework.context.config.ContextNamespaceHandler
:
public class ContextNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
}
load-time-weaver
解析類爲: LoadTimeWeaverBeanDefinitionParser
.解析邏輯主要集中在doParse
方法中:
protected String getBeanClassName(Element element) {
if (element.hasAttribute(WEAVER_CLASS_ATTRIBUTE)) {
return element.getAttribute(WEAVER_CLASS_ATTRIBUTE);
}
return DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME;
}
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) {
return ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME;
}
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
if (isAspectJWeavingEnabled(element.getAttribute(ASPECTJ_WEAVING_ATTRIBUTE), parserContext)) {
if (!parserContext.getRegistry().containsBeanDefinition(ASPECTJ_WEAVING_ENABLER_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ASPECTJ_WEAVING_ENABLER_CLASS_NAME);
parserContext.registerBeanComponent(
new BeanComponentDefinition(def, ASPECTJ_WEAVING_ENABLER_BEAN_NAME));
}
if (isBeanConfigurerAspectEnabled(parserContext.getReaderContext().getBeanClassLoader())) {
new SpringConfiguredBeanDefinitionParser().parse(element, parserContext);
}
}
}
protected boolean isAspectJWeavingEnabled(String value, ParserContext parserContext) {
if ("on".equals(value)) {
return true;
}
else if ("off".equals(value)) {
return false;
}
else {
// Determine default...
ClassLoader cl = parserContext.getReaderContext().getBeanClassLoader();
return (cl != null && cl.getResource(AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE) != null);
}
}
判斷是否啓用AspectJ的邏輯是:
- 如果配置
aspectj-weaving=on
則表示開啓 - 如果配置
aspectj-weaving=off
則表示不開啓,關閉 - 其他情況,判斷當前環境下是否存在
META-INF/aop.xml
,如果存在,表示開啓AspectJ
如果確認需要開啓AspectJ,則會向IOC容器中,註冊org.springframework.context.weaving.AspectJWeavingEnabler
和
org.springframework.context.weaving.DefaultContextLoadTimeWeaver
這裏DefaultContextLoadTimeWeaver是默認實現,如果在 \<context:load-time-weaver weaver-class="xxxx.xxx"/> 配置了
weaver-class這裏會註冊該類
這兩個對應名稱爲:
ASPECTJ_WEAVING_ENABLER_BEAN_NAME =
“org.springframework.context.config.internalAspectJWeavingEnabler” -> AspectJWeavingEnabler
上面這幾步,完成了AspectJ的相關準備工作,但是並沒有進行織入,前面我們在研究spring容器啓動過程分析的時候,有一步是進行AspectJ的織入。
spring容器啓動過程分析
在AbstactApplicationContext.invokeBeanFactoryPostProcessors時候,會加入LoadTimeWeaverAwareProcessor
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
LoadTimeWeaverAwareProcessor.postProcessBeforeInitialization
邏輯:
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LoadTimeWeaverAware) {
LoadTimeWeaver ltw = this.loadTimeWeaver;
if (ltw == null) {
Assert.state(this.beanFactory != null,
"BeanFactory required if no LoadTimeWeaver explicitly specified");
ltw = this.beanFactory.getBean(
ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME, LoadTimeWeaver.class);
}
((LoadTimeWeaverAware) bean).setLoadTimeWeaver(ltw);
}
return bean;
}
這裏首先會判斷當前處理bean是否是LoadTimeWeaverAware
,整個spirng中只有前面提到的AspectJWeavingEnabler
實現了該接口。
而此時this.loadTimeWeaver
並沒有實例化,直接通過getBean獲取,此時獲取的就是之前說過的DefaultContextLoadTimeWeaver(或者手動指定)
。
DefaultContextLoadTimeWeaver實現了BeanClassLoaderAware接口,在其setBeanClassLoader
邏輯:
// DefaultContextLoadTimeWeaver.java
public void setBeanClassLoader(ClassLoader classLoader) {
LoadTimeWeaver serverSpecificLoadTimeWeaver = createServerSpecificLoadTimeWeaver(classLoader);
if (serverSpecificLoadTimeWeaver != null) {
if (logger.isDebugEnabled()) {
logger.debug("Determined server-specific load-time weaver: " +
serverSpecificLoadTimeWeaver.getClass().getName());
}
this.loadTimeWeaver = serverSpecificLoadTimeWeaver;
}
else if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
logger.debug("Found Spring's JVM agent for instrumentation");
this.loadTimeWeaver = new InstrumentationLoadTimeWeaver(classLoader);
}
else {
try {
this.loadTimeWeaver = new ReflectiveLoadTimeWeaver(classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Using reflective load-time weaver for class loader: " +
this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName());
}
}
catch (IllegalStateException ex) {
throw new IllegalStateException(ex.getMessage() + " Specify a custom LoadTimeWeaver or start your " +
"Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar");
}
}
}
其中:
else if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
logger.debug(“Found Spring’s JVM agent for instrumentation”);
this.loadTimeWeaver = new InstrumentationLoadTimeWeaver(classLoader);
}
經過上述處理後,
AspectJWeavingEnabler.loadTimeWeaver = DefaultContextLoadTimeWeaver
DefaultContextLoadTimeWeaver.loadTimeWeaver = InstrumentationLoadTimeWeaver
AspectJWeavingEnabler同時實現了BeanFactoryPostProcessor,其postProcessBeanFactory
實現如下:
// AspectJWeavingEnabler.java
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
enableAspectJWeaving(this.loadTimeWeaver, this.beanClassLoader);
}
/**
* Enable AspectJ weaving with the given {@link LoadTimeWeaver}.
* @param weaverToUse the LoadTimeWeaver to apply to (or {@code null} for a default weaver)
* @param beanClassLoader the class loader to create a default weaver for (if necessary)
*/
public static void enableAspectJWeaving(
@Nullable LoadTimeWeaver weaverToUse, @Nullable ClassLoader beanClassLoader) {
if (weaverToUse == null) {
if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
weaverToUse = new InstrumentationLoadTimeWeaver(beanClassLoader);
}
else {
throw new IllegalStateException("No LoadTimeWeaver available");
}
}
weaverToUse.addTransformer(
new AspectJClassBypassingClassFileTransformer(new ClassPreProcessorAgentAdapter()));
}
/**
* ClassFileTransformer decorator that suppresses processing of AspectJ
* classes in order to avoid potential LinkageErrors.
* @see org.springframework.context.annotation.LoadTimeWeavingConfiguration
*/
private static class AspectJClassBypassingClassFileTransformer implements ClassFileTransformer {
private final ClassFileTransformer delegate;
public AspectJClassBypassingClassFileTransformer(ClassFileTransformer delegate) {
this.delegate = delegate;
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
if (className.startsWith("org.aspectj") || className.startsWith("org/aspectj")) {
return classfileBuffer;
}
// 委託給AspectJ繼續處理
return this.delegate.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
}
}