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