001/*
002 * Copyright 2002-2018 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.weaving;
018
019import java.lang.instrument.ClassFileTransformer;
020import java.lang.instrument.IllegalClassFormatException;
021import java.security.ProtectionDomain;
022
023import org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter;
024
025import org.springframework.beans.BeansException;
026import org.springframework.beans.factory.BeanClassLoaderAware;
027import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
028import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
029import org.springframework.core.Ordered;
030import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver;
031import org.springframework.instrument.classloading.LoadTimeWeaver;
032import org.springframework.lang.Nullable;
033
034/**
035 * Post-processor that registers AspectJ's
036 * {@link org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter}
037 * with the Spring application context's default
038 * {@link org.springframework.instrument.classloading.LoadTimeWeaver}.
039 *
040 * @author Juergen Hoeller
041 * @author Ramnivas Laddad
042 * @since 2.5
043 */
044public class AspectJWeavingEnabler
045                implements BeanFactoryPostProcessor, BeanClassLoaderAware, LoadTimeWeaverAware, Ordered {
046
047        /**
048         * The {@code aop.xml} resource location.
049         */
050        public static final String ASPECTJ_AOP_XML_RESOURCE = "META-INF/aop.xml";
051
052
053        @Nullable
054        private ClassLoader beanClassLoader;
055
056        @Nullable
057        private LoadTimeWeaver loadTimeWeaver;
058
059
060        @Override
061        public void setBeanClassLoader(ClassLoader classLoader) {
062                this.beanClassLoader = classLoader;
063        }
064
065        @Override
066        public void setLoadTimeWeaver(LoadTimeWeaver loadTimeWeaver) {
067                this.loadTimeWeaver = loadTimeWeaver;
068        }
069
070        @Override
071        public int getOrder() {
072                return HIGHEST_PRECEDENCE;
073        }
074
075        @Override
076        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
077                enableAspectJWeaving(this.loadTimeWeaver, this.beanClassLoader);
078        }
079
080
081        /**
082         * Enable AspectJ weaving with the given {@link LoadTimeWeaver}.
083         * @param weaverToUse the LoadTimeWeaver to apply to (or {@code null} for a default weaver)
084         * @param beanClassLoader the class loader to create a default weaver for (if necessary)
085         */
086        public static void enableAspectJWeaving(
087                        @Nullable LoadTimeWeaver weaverToUse, @Nullable ClassLoader beanClassLoader) {
088
089                if (weaverToUse == null) {
090                        if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) {
091                                weaverToUse = new InstrumentationLoadTimeWeaver(beanClassLoader);
092                        }
093                        else {
094                                throw new IllegalStateException("No LoadTimeWeaver available");
095                        }
096                }
097                weaverToUse.addTransformer(
098                                new AspectJClassBypassingClassFileTransformer(new ClassPreProcessorAgentAdapter()));
099        }
100
101
102        /**
103         * ClassFileTransformer decorator that suppresses processing of AspectJ
104         * classes in order to avoid potential LinkageErrors.
105         * @see org.springframework.context.annotation.LoadTimeWeavingConfiguration
106         */
107        private static class AspectJClassBypassingClassFileTransformer implements ClassFileTransformer {
108
109                private final ClassFileTransformer delegate;
110
111                public AspectJClassBypassingClassFileTransformer(ClassFileTransformer delegate) {
112                        this.delegate = delegate;
113                }
114
115                @Override
116                public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
117                                ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
118
119                        if (className.startsWith("org.aspectj") || className.startsWith("org/aspectj")) {
120                                return classfileBuffer;
121                        }
122                        return this.delegate.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
123                }
124        }
125
126}