Skip to content

Commit 620018d

Browse files
committed
Introduce @EnableLoadTimeWeaving
Issue: SPR-8317
1 parent bce9149 commit 620018d

File tree

9 files changed

+396
-16
lines changed

9 files changed

+396
-16
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/*
2+
* Copyright 2002-2011 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.context.annotation;
18+
19+
import java.lang.annotation.Documented;
20+
import java.lang.annotation.ElementType;
21+
import java.lang.annotation.Retention;
22+
import java.lang.annotation.RetentionPolicy;
23+
import java.lang.annotation.Target;
24+
25+
import org.springframework.context.weaving.DefaultContextLoadTimeWeaver;
26+
import org.springframework.instrument.classloading.LoadTimeWeaver;
27+
28+
/**
29+
* Activates a Spring {@link LoadTimeWeaver} for this application context, available as
30+
* a bean with the name "loadTimeWeaver", similar to the {@code <context:load-time-weaver>}
31+
* element in Spring XML.
32+
* To be used
33+
* on @{@link org.springframework.context.annotation.Configuration Configuration} classes;
34+
* the simplest possible example of which follows:
35+
* <pre class="code">
36+
* &#064;Configuration
37+
* &#064;EnableLoadTimeWeaving
38+
* public class AppConfig {
39+
* // application-specific &#064;Bean definitions ...
40+
* }</pre>
41+
*
42+
* The example above is equivalent to the following Spring XML configuration:
43+
* <pre class="code">
44+
* {@code
45+
* <beans>
46+
* <context:load-time-weaver/>
47+
* <!-- application-specific <bean> definitions -->
48+
* </beans>
49+
* }</pre>
50+
*
51+
* <h2>The {@code LoadTimeWeaverAware} interface</h2>
52+
* Any bean that implements the {@link
53+
* org.springframework.context.weaving.LoadTimeWeaverAware LoadTimeWeaverAware} interface
54+
* will then receive the {@code LoadTimeWeaver} reference automatically; for example,
55+
* Spring's JPA bootstrap support.
56+
*
57+
* <h2>Customizing the {@code LoadTimeWeaver}</h2>
58+
* The default weaver is determined automatically. As of Spring 3.1: detecting
59+
* Sun's GlassFish, Oracle's OC4J, Spring's VM agent and any ClassLoader supported by
60+
* Spring's {@link
61+
* org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver
62+
* ReflectiveLoadTimeWeaver} (for example, the {@link
63+
* org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader
64+
* TomcatInstrumentableClassLoader}).
65+
*
66+
* <p>To customize the weaver used, the {@code @Configuration} class annotated with
67+
* {@code @EnableLoadTimeWeaving} may also implement the {@link LoadTimeWeaverConfigurer}
68+
* interface and return a custom {@code LoadTimeWeaver} instance through the
69+
* {@code #getLoadTimeWeaver} method:
70+
* <pre class="code">
71+
* &#064;Configuration
72+
* &#064;EnableLoadTimeWeaving
73+
* public class AppConfig implements LoadTimeWeaverConfigurer {
74+
* &#064;Override
75+
* public LoadTimeWeaver getLoadTimeWeaver() {
76+
* MyLoadTimeWeaver ltw = new MyLoadTimeWeaver();
77+
* ltw.addClassTransformer(myClassFileTransformer);
78+
* // ...
79+
* return ltw;
80+
* }
81+
* }</pre>
82+
*
83+
* <p>The example above can be compared to the following Spring XML configuration:
84+
* <pre class="code">
85+
* {@code
86+
* <beans>
87+
* <context:load-time-weaver weaverClass="com.acme.MyLoadTimeWeaver"/>
88+
* </beans>
89+
* }</pre>
90+
*
91+
* <p>The code example differs from the XML example in that it actually instantiates the
92+
* {@code MyLoadTimeWeaver} type, meaning that it can also configure the instance, e.g.
93+
* calling the {@code #addClassTransformer} method. This demonstrates how the code-based
94+
* configuration approach is more flexible through direct programmatic access.
95+
*
96+
* <h2>Enabling AspectJ-based weaving</h2>
97+
* AspectJ load-time weaving may be enabled with the {@link #aspectjWeaving()}
98+
* attribute, which will cause the {@linkplain
99+
* org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter AspectJ class transformer} to
100+
* be registered through {@link LoadTimeWeaver#addTransformer}. AspectJ weaving will be
101+
* activated by default if a "META-INF/aop.xml" resource is present on the classpath.
102+
* Example:
103+
* <pre class="code">
104+
* &#064;Configuration
105+
* &#064;EnableLoadTimeWeaving(aspectjWeaving=ENABLED)
106+
* public class AppConfig {
107+
* }</pre>
108+
*
109+
* <p>The example above can be compared to the following Spring XML configuration:
110+
* <pre class="code">
111+
* {@code
112+
* <beans>
113+
* <context:load-time-weaver aspectj-weaving="on"/>
114+
* </beans>
115+
* }</pre>
116+
*
117+
* <p>The two examples are equivalent with one significant exception: in the XML case,
118+
* the functionality of {@code <context:spring-configured>} is implicitly enabled when
119+
* {@code aspectj-weaving} is "on". This does not occur when using
120+
* {@code @EnableLoadTimeWeaving(aspectjWeaving=ENABLED)}, although this may change in
121+
* future revisions.
122+
*
123+
* @author Chris Beams
124+
* @since 3.1
125+
* @see LoadTimeWeaver
126+
* @see DefaultContextLoadTimeWeaver
127+
* @see org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter
128+
*/
129+
@Target(ElementType.TYPE)
130+
@Retention(RetentionPolicy.RUNTIME)
131+
@Documented
132+
@Import(LoadTimeWeavingConfiguration.class)
133+
public @interface EnableLoadTimeWeaving {
134+
135+
/**
136+
* Whether AspectJ weaving should be enabled.
137+
*/
138+
AspectJWeaving aspectjWeaving() default AspectJWeaving.AUTODETECT;
139+
140+
public enum AspectJWeaving {
141+
142+
/**
143+
* Switches on Spring-based AspectJ load-time weaving.
144+
*/
145+
ENABLED,
146+
147+
/**
148+
* Switches off Spring-based AspectJ load-time weaving (even if a
149+
* "META-INF/aop.xml" resource is present on the classpath).
150+
*/
151+
DISABLED,
152+
153+
/**
154+
* Switches on AspectJ load-time weaving if a "META-INF/aop.xml" resource
155+
* is present in the classpath. If there is no such resource, then AspectJ
156+
* load-time weaving will be switched off.
157+
*/
158+
AUTODETECT;
159+
}
160+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2002-2011 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.context.annotation;
18+
19+
import static org.springframework.context.weaving.AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE;
20+
21+
import java.util.Map;
22+
23+
import org.springframework.beans.factory.BeanClassLoaderAware;
24+
import org.springframework.beans.factory.annotation.Autowired;
25+
import org.springframework.beans.factory.config.BeanDefinition;
26+
import org.springframework.context.ConfigurableApplicationContext;
27+
import org.springframework.context.annotation.EnableLoadTimeWeaving.AspectJWeaving;
28+
import org.springframework.context.weaving.AspectJWeavingEnabler;
29+
import org.springframework.context.weaving.DefaultContextLoadTimeWeaver;
30+
import org.springframework.core.type.AnnotationMetadata;
31+
import org.springframework.instrument.classloading.LoadTimeWeaver;
32+
import org.springframework.util.Assert;
33+
34+
/**
35+
* {@code @Configuration} class that registers a {@link LoadTimeWeaver} bean.
36+
*
37+
* <p>This configuration class is automatically imported when using the @{@link
38+
* EnableLoadTimeWeaving} annotation. See {@code @EnableLoadTimeWeaving} Javadoc for
39+
* complete usage details.
40+
*
41+
* @author Chris Beams
42+
* @since 3.1
43+
* @see LoadTimeWeavingConfigurer
44+
* @see ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME
45+
*/
46+
@Configuration
47+
public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoaderAware {
48+
49+
private Map<String, Object> enableLTW;
50+
51+
@Autowired(required=false)
52+
private LoadTimeWeavingConfigurer ltwConfigurer;
53+
54+
private ClassLoader beanClassLoader;
55+
56+
public void setImportMetadata(AnnotationMetadata importMetadata) {
57+
this.enableLTW = importMetadata.getAnnotationAttributes(EnableLoadTimeWeaving.class.getName(), false);
58+
Assert.notNull(this.enableLTW,
59+
"@EnableLoadTimeWeaving is not present on importing class " +
60+
importMetadata.getClassName());
61+
}
62+
63+
public void setBeanClassLoader(ClassLoader beanClassLoader) {
64+
this.beanClassLoader = beanClassLoader;
65+
}
66+
67+
@Bean(name=ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME)
68+
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
69+
public LoadTimeWeaver loadTimeWeaver() {
70+
LoadTimeWeaver loadTimeWeaver = null;
71+
72+
if (ltwConfigurer != null) {
73+
// the user has provided a custom LTW instance
74+
loadTimeWeaver = ltwConfigurer.getLoadTimeWeaver();
75+
}
76+
77+
if (loadTimeWeaver == null) {
78+
// no custom LTW provided -> fall back to the default
79+
loadTimeWeaver = new DefaultContextLoadTimeWeaver(this.beanClassLoader);
80+
}
81+
82+
switch ((AspectJWeaving) this.enableLTW.get("aspectjWeaving")) {
83+
case DISABLED:
84+
// AJ weaving is disabled -> do nothing
85+
break;
86+
case AUTODETECT:
87+
if (this.beanClassLoader.getResource(ASPECTJ_AOP_XML_RESOURCE) != null) {
88+
// No aop.xml present on the classpath -> treat as 'disabled'
89+
break;
90+
}
91+
// aop.xml is present on the classpath -> fall through and enable
92+
case ENABLED:
93+
AspectJWeavingEnabler.enableAspectJWeaving(loadTimeWeaver, this.beanClassLoader);
94+
}
95+
96+
return loadTimeWeaver;
97+
}
98+
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2002-2011 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.context.annotation;
18+
19+
import org.springframework.instrument.classloading.LoadTimeWeaver;
20+
21+
/**
22+
* Interface to be implemented by @{@link org.springframework.context.annotation.Configuration
23+
* Configuration} classes annotated with @{@link EnableLoadTimeWeaving} that wish to
24+
* customize the {@link LoadTimeWeaver} instance to be used.
25+
*
26+
* <p>See @{@link EnableAsync} for usage examples and information on how a default
27+
* {@code LoadTimeWeaver} is selected when this interface is not used.
28+
*
29+
* @author Chris Beams
30+
* @since 3.1
31+
* @see LoadTimeWeavingConfiguration
32+
* @see EnableLoadTimeWeaving
33+
*/
34+
public interface LoadTimeWeavingConfigurer {
35+
36+
/**
37+
* Create, configure and return the {@code LoadTimeWeaver} instance to be used. Note
38+
* that it is unnecessary to annotate this method with {@code @Bean}, because the
39+
* object returned will automatically be registered as a bean by
40+
* {@link LoadTimeWeavingConfiguration#loadTimeWeaver()}
41+
*/
42+
LoadTimeWeaver getLoadTimeWeaver();
43+
44+
}

org.springframework.context/src/main/java/org/springframework/context/config/LoadTimeWeaverBeanDefinitionParser.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2007 the original author or authors.
2+
* Copyright 2002-2011 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
2525
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
2626
import org.springframework.beans.factory.xml.ParserContext;
2727
import org.springframework.context.ConfigurableApplicationContext;
28+
import org.springframework.context.weaving.AspectJWeavingEnabler;
2829
import org.springframework.util.ClassUtils;
2930

3031
/**
@@ -39,8 +40,6 @@ class LoadTimeWeaverBeanDefinitionParser extends AbstractSingleBeanDefinitionPar
3940

4041
private static final String ASPECTJ_WEAVING_ATTRIBUTE = "aspectj-weaving";
4142

42-
private static final String ASPECTJ_AOP_XML_RESOURCE = "META-INF/aop.xml";
43-
4443
private static final String DEFAULT_LOAD_TIME_WEAVER_CLASS_NAME =
4544
"org.springframework.context.weaving.DefaultContextLoadTimeWeaver";
4645

@@ -86,7 +85,7 @@ else if ("off".equals(value)) {
8685
else {
8786
// Determine default...
8887
ClassLoader cl = parserContext.getReaderContext().getResourceLoader().getClassLoader();
89-
return (cl.getResource(ASPECTJ_AOP_XML_RESOURCE) != null);
88+
return (cl.getResource(AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE) != null);
9089
}
9190
}
9291

0 commit comments

Comments
 (0)