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; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023 024import org.springframework.beans.factory.BeanClassLoaderAware; 025import org.springframework.beans.factory.DisposableBean; 026import org.springframework.instrument.InstrumentationSavingAgent; 027import org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver; 028import org.springframework.instrument.classloading.LoadTimeWeaver; 029import org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver; 030import org.springframework.instrument.classloading.glassfish.GlassFishLoadTimeWeaver; 031import org.springframework.instrument.classloading.jboss.JBossLoadTimeWeaver; 032import org.springframework.instrument.classloading.tomcat.TomcatLoadTimeWeaver; 033import org.springframework.instrument.classloading.weblogic.WebLogicLoadTimeWeaver; 034import org.springframework.instrument.classloading.websphere.WebSphereLoadTimeWeaver; 035 036/** 037 * Default {@link LoadTimeWeaver} bean for use in an application context, 038 * decorating an automatically detected internal {@code LoadTimeWeaver}. 039 * 040 * <p>Typically registered for the default bean name 041 * "{@code loadTimeWeaver}"; the most convenient way to achieve this is 042 * Spring's {@code <context:load-time-weaver>} XML tag. 043 * 044 * <p>This class implements a runtime environment check for obtaining the 045 * appropriate weaver implementation: As of Spring 4.0, it detects Oracle WebLogic 10, 046 * GlassFish 3, Tomcat 6, 7 and 8, JBoss AS 5, 6 and 7, IBM WebSphere 7 and 8, 047 * {@link InstrumentationSavingAgent Spring's VM agent}, and any {@link ClassLoader} 048 * supported by Spring's {@link ReflectiveLoadTimeWeaver}. 049 * 050 * @author Juergen Hoeller 051 * @author Ramnivas Laddad 052 * @author Costin Leau 053 * @since 2.5 054 * @see org.springframework.context.ConfigurableApplicationContext#LOAD_TIME_WEAVER_BEAN_NAME 055 */ 056public class DefaultContextLoadTimeWeaver implements LoadTimeWeaver, BeanClassLoaderAware, DisposableBean { 057 058 protected final Log logger = LogFactory.getLog(getClass()); 059 060 private LoadTimeWeaver loadTimeWeaver; 061 062 063 public DefaultContextLoadTimeWeaver() { 064 } 065 066 public DefaultContextLoadTimeWeaver(ClassLoader beanClassLoader) { 067 setBeanClassLoader(beanClassLoader); 068 } 069 070 071 @Override 072 public void setBeanClassLoader(ClassLoader classLoader) { 073 LoadTimeWeaver serverSpecificLoadTimeWeaver = createServerSpecificLoadTimeWeaver(classLoader); 074 if (serverSpecificLoadTimeWeaver != null) { 075 if (logger.isInfoEnabled()) { 076 logger.info("Determined server-specific load-time weaver: " + 077 serverSpecificLoadTimeWeaver.getClass().getName()); 078 } 079 this.loadTimeWeaver = serverSpecificLoadTimeWeaver; 080 } 081 else if (InstrumentationLoadTimeWeaver.isInstrumentationAvailable()) { 082 logger.info("Found Spring's JVM agent for instrumentation"); 083 this.loadTimeWeaver = new InstrumentationLoadTimeWeaver(classLoader); 084 } 085 else { 086 try { 087 this.loadTimeWeaver = new ReflectiveLoadTimeWeaver(classLoader); 088 if (logger.isInfoEnabled()) { 089 logger.info("Using a reflective load-time weaver for class loader: " + 090 this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName()); 091 } 092 } 093 catch (IllegalStateException ex) { 094 throw new IllegalStateException(ex.getMessage() + " Specify a custom LoadTimeWeaver or start your " + 095 "Java virtual machine with Spring's agent: -javaagent:org.springframework.instrument.jar"); 096 } 097 } 098 } 099 100 /* 101 * This method never fails, allowing to try other possible ways to use an 102 * server-agnostic weaver. This non-failure logic is required since 103 * determining a load-time weaver based on the ClassLoader name alone may 104 * legitimately fail due to other mismatches. Specific case in point: the 105 * use of WebLogicLoadTimeWeaver works for WLS 10 but fails due to the lack 106 * of a specific method (addInstanceClassPreProcessor) for any earlier 107 * versions even though the ClassLoader name is the same. 108 */ 109 protected LoadTimeWeaver createServerSpecificLoadTimeWeaver(ClassLoader classLoader) { 110 String name = classLoader.getClass().getName(); 111 try { 112 if (name.startsWith("org.apache.catalina")) { 113 return new TomcatLoadTimeWeaver(classLoader); 114 } 115 else if (name.startsWith("org.glassfish")) { 116 return new GlassFishLoadTimeWeaver(classLoader); 117 } 118 else if (name.startsWith("org.jboss")) { 119 return new JBossLoadTimeWeaver(classLoader); 120 } 121 else if (name.startsWith("com.ibm")) { 122 return new WebSphereLoadTimeWeaver(classLoader); 123 } 124 else if (name.startsWith("weblogic")) { 125 return new WebLogicLoadTimeWeaver(classLoader); 126 } 127 } 128 catch (Exception ex) { 129 if (logger.isInfoEnabled()) { 130 logger.info("Could not obtain server-specific LoadTimeWeaver: " + ex.getMessage()); 131 } 132 } 133 return null; 134 } 135 136 @Override 137 public void destroy() { 138 if (this.loadTimeWeaver instanceof InstrumentationLoadTimeWeaver) { 139 if (logger.isInfoEnabled()) { 140 logger.info("Removing all registered transformers for class loader: " + 141 this.loadTimeWeaver.getInstrumentableClassLoader().getClass().getName()); 142 } 143 ((InstrumentationLoadTimeWeaver) this.loadTimeWeaver).removeTransformers(); 144 } 145 } 146 147 148 @Override 149 public void addTransformer(ClassFileTransformer transformer) { 150 this.loadTimeWeaver.addTransformer(transformer); 151 } 152 153 @Override 154 public ClassLoader getInstrumentableClassLoader() { 155 return this.loadTimeWeaver.getInstrumentableClassLoader(); 156 } 157 158 @Override 159 public ClassLoader getThrowawayClassLoader() { 160 return this.loadTimeWeaver.getThrowawayClassLoader(); 161 } 162 163}