001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.context.annotation;
018
019import org.springframework.beans.factory.BeanClassLoaderAware;
020import org.springframework.beans.factory.annotation.Autowired;
021import org.springframework.beans.factory.config.BeanDefinition;
022import org.springframework.context.ConfigurableApplicationContext;
023import org.springframework.context.annotation.EnableLoadTimeWeaving.AspectJWeaving;
024import org.springframework.context.weaving.AspectJWeavingEnabler;
025import org.springframework.context.weaving.DefaultContextLoadTimeWeaver;
026import org.springframework.core.annotation.AnnotationAttributes;
027import org.springframework.core.type.AnnotationMetadata;
028import org.springframework.instrument.classloading.LoadTimeWeaver;
029import org.springframework.lang.Nullable;
030import org.springframework.util.Assert;
031
032/**
033 * {@code @Configuration} class that registers a {@link LoadTimeWeaver} bean.
034 *
035 * <p>This configuration class is automatically imported when using the
036 * {@link EnableLoadTimeWeaving} annotation. See {@code @EnableLoadTimeWeaving}
037 * javadoc for complete usage details.
038 *
039 * @author Chris Beams
040 * @since 3.1
041 * @see LoadTimeWeavingConfigurer
042 * @see ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME
043 */
044@Configuration
045@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
046public class LoadTimeWeavingConfiguration implements ImportAware, BeanClassLoaderAware {
047
048        @Nullable
049        private AnnotationAttributes enableLTW;
050
051        @Nullable
052        private LoadTimeWeavingConfigurer ltwConfigurer;
053
054        @Nullable
055        private ClassLoader beanClassLoader;
056
057
058        @Override
059        public void setImportMetadata(AnnotationMetadata importMetadata) {
060                this.enableLTW = AnnotationConfigUtils.attributesFor(importMetadata, EnableLoadTimeWeaving.class);
061                if (this.enableLTW == null) {
062                        throw new IllegalArgumentException(
063                                        "@EnableLoadTimeWeaving is not present on importing class " + importMetadata.getClassName());
064                }
065        }
066
067        @Autowired(required = false)
068        public void setLoadTimeWeavingConfigurer(LoadTimeWeavingConfigurer ltwConfigurer) {
069                this.ltwConfigurer = ltwConfigurer;
070        }
071
072        @Override
073        public void setBeanClassLoader(ClassLoader beanClassLoader) {
074                this.beanClassLoader = beanClassLoader;
075        }
076
077
078        @Bean(name = ConfigurableApplicationContext.LOAD_TIME_WEAVER_BEAN_NAME)
079        @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
080        public LoadTimeWeaver loadTimeWeaver() {
081                Assert.state(this.beanClassLoader != null, "No ClassLoader set");
082                LoadTimeWeaver loadTimeWeaver = null;
083
084                if (this.ltwConfigurer != null) {
085                        // The user has provided a custom LoadTimeWeaver instance
086                        loadTimeWeaver = this.ltwConfigurer.getLoadTimeWeaver();
087                }
088
089                if (loadTimeWeaver == null) {
090                        // No custom LoadTimeWeaver provided -> fall back to the default
091                        loadTimeWeaver = new DefaultContextLoadTimeWeaver(this.beanClassLoader);
092                }
093
094                if (this.enableLTW != null) {
095                        AspectJWeaving aspectJWeaving = this.enableLTW.getEnum("aspectjWeaving");
096                        switch (aspectJWeaving) {
097                                case DISABLED:
098                                        // AJ weaving is disabled -> do nothing
099                                        break;
100                                case AUTODETECT:
101                                        if (this.beanClassLoader.getResource(AspectJWeavingEnabler.ASPECTJ_AOP_XML_RESOURCE) == null) {
102                                                // No aop.xml present on the classpath -> treat as 'disabled'
103                                                break;
104                                        }
105                                        // aop.xml is present on the classpath -> enable
106                                        AspectJWeavingEnabler.enableAspectJWeaving(loadTimeWeaver, this.beanClassLoader);
107                                        break;
108                                case ENABLED:
109                                        AspectJWeavingEnabler.enableAspectJWeaving(loadTimeWeaver, this.beanClassLoader);
110                                        break;
111                        }
112                }
113
114                return loadTimeWeaver;
115        }
116
117}