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}