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.aop.aspectj.annotation; 018 019import java.util.List; 020import java.util.Map; 021import java.util.concurrent.ConcurrentHashMap; 022 023import org.aspectj.lang.reflect.PerClauseKind; 024 025import org.springframework.aop.Advisor; 026import org.springframework.aop.aspectj.AspectJProxyUtils; 027import org.springframework.aop.framework.AopConfigException; 028import org.springframework.aop.framework.ProxyCreatorSupport; 029import org.springframework.aop.support.AopUtils; 030import org.springframework.core.annotation.AnnotationAwareOrderComparator; 031import org.springframework.util.Assert; 032import org.springframework.util.ClassUtils; 033 034/** 035 * AspectJ-based proxy factory, allowing for programmatic building 036 * of proxies which include AspectJ aspects (code style as well 037 * Java 5 annotation style). 038 * 039 * @author Rob Harrop 040 * @author Juergen Hoeller 041 * @author Ramnivas Laddad 042 * @since 2.0 043 * @see #addAspect(Object) 044 * @see #addAspect(Class) 045 * @see #getProxy() 046 * @see #getProxy(ClassLoader) 047 * @see org.springframework.aop.framework.ProxyFactory 048 */ 049@SuppressWarnings("serial") 050public class AspectJProxyFactory extends ProxyCreatorSupport { 051 052 /** Cache for singleton aspect instances */ 053 private static final Map<Class<?>, Object> aspectCache = new ConcurrentHashMap<Class<?>, Object>(); 054 055 private final AspectJAdvisorFactory aspectFactory = new ReflectiveAspectJAdvisorFactory(); 056 057 058 /** 059 * Create a new AspectJProxyFactory. 060 */ 061 public AspectJProxyFactory() { 062 } 063 064 /** 065 * Create a new AspectJProxyFactory. 066 * <p>Will proxy all interfaces that the given target implements. 067 * @param target the target object to be proxied 068 */ 069 public AspectJProxyFactory(Object target) { 070 Assert.notNull(target, "Target object must not be null"); 071 setInterfaces(ClassUtils.getAllInterfaces(target)); 072 setTarget(target); 073 } 074 075 /** 076 * Create a new {@code AspectJProxyFactory}. 077 * No target, only interfaces. Must add interceptors. 078 */ 079 public AspectJProxyFactory(Class<?>... interfaces) { 080 setInterfaces(interfaces); 081 } 082 083 084 /** 085 * Add the supplied aspect instance to the chain. The type of the aspect instance 086 * supplied must be a singleton aspect. True singleton lifecycle is not honoured when 087 * using this method - the caller is responsible for managing the lifecycle of any 088 * aspects added in this way. 089 * @param aspectInstance the AspectJ aspect instance 090 */ 091 public void addAspect(Object aspectInstance) { 092 Class<?> aspectClass = aspectInstance.getClass(); 093 String aspectName = aspectClass.getName(); 094 AspectMetadata am = createAspectMetadata(aspectClass, aspectName); 095 if (am.getAjType().getPerClause().getKind() != PerClauseKind.SINGLETON) { 096 throw new IllegalArgumentException( 097 "Aspect class [" + aspectClass.getName() + "] does not define a singleton aspect"); 098 } 099 addAdvisorsFromAspectInstanceFactory( 100 new SingletonMetadataAwareAspectInstanceFactory(aspectInstance, aspectName)); 101 } 102 103 /** 104 * Add an aspect of the supplied type to the end of the advice chain. 105 * @param aspectClass the AspectJ aspect class 106 */ 107 public void addAspect(Class<?> aspectClass) { 108 String aspectName = aspectClass.getName(); 109 AspectMetadata am = createAspectMetadata(aspectClass, aspectName); 110 MetadataAwareAspectInstanceFactory instanceFactory = createAspectInstanceFactory(am, aspectClass, aspectName); 111 addAdvisorsFromAspectInstanceFactory(instanceFactory); 112 } 113 114 115 /** 116 * Add all {@link Advisor Advisors} from the supplied {@link MetadataAwareAspectInstanceFactory} 117 * to the current chain. Exposes any special purpose {@link Advisor Advisors} if needed. 118 * @see AspectJProxyUtils#makeAdvisorChainAspectJCapableIfNecessary(List) 119 */ 120 private void addAdvisorsFromAspectInstanceFactory(MetadataAwareAspectInstanceFactory instanceFactory) { 121 List<Advisor> advisors = this.aspectFactory.getAdvisors(instanceFactory); 122 advisors = AopUtils.findAdvisorsThatCanApply(advisors, getTargetClass()); 123 AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(advisors); 124 AnnotationAwareOrderComparator.sort(advisors); 125 addAdvisors(advisors); 126 } 127 128 /** 129 * Create an {@link AspectMetadata} instance for the supplied aspect type. 130 */ 131 private AspectMetadata createAspectMetadata(Class<?> aspectClass, String aspectName) { 132 AspectMetadata am = new AspectMetadata(aspectClass, aspectName); 133 if (!am.getAjType().isAspect()) { 134 throw new IllegalArgumentException("Class [" + aspectClass.getName() + "] is not a valid aspect type"); 135 } 136 return am; 137 } 138 139 /** 140 * Create a {@link MetadataAwareAspectInstanceFactory} for the supplied aspect type. If the aspect type 141 * has no per clause, then a {@link SingletonMetadataAwareAspectInstanceFactory} is returned, otherwise 142 * a {@link PrototypeAspectInstanceFactory} is returned. 143 */ 144 private MetadataAwareAspectInstanceFactory createAspectInstanceFactory( 145 AspectMetadata am, Class<?> aspectClass, String aspectName) { 146 147 MetadataAwareAspectInstanceFactory instanceFactory; 148 if (am.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) { 149 // Create a shared aspect instance. 150 Object instance = getSingletonAspectInstance(aspectClass); 151 instanceFactory = new SingletonMetadataAwareAspectInstanceFactory(instance, aspectName); 152 } 153 else { 154 // Create a factory for independent aspect instances. 155 instanceFactory = new SimpleMetadataAwareAspectInstanceFactory(aspectClass, aspectName); 156 } 157 return instanceFactory; 158 } 159 160 /** 161 * Get the singleton aspect instance for the supplied aspect type. An instance 162 * is created if one cannot be found in the instance cache. 163 */ 164 private Object getSingletonAspectInstance(Class<?> aspectClass) { 165 // Quick check without a lock... 166 Object instance = aspectCache.get(aspectClass); 167 if (instance == null) { 168 synchronized (aspectCache) { 169 // To be safe, check within full lock now... 170 instance = aspectCache.get(aspectClass); 171 if (instance == null) { 172 try { 173 instance = aspectClass.newInstance(); 174 aspectCache.put(aspectClass, instance); 175 } 176 catch (InstantiationException ex) { 177 throw new AopConfigException( 178 "Unable to instantiate aspect class: " + aspectClass.getName(), ex); 179 } 180 catch (IllegalAccessException ex) { 181 throw new AopConfigException( 182 "Could not access aspect constructor: " + aspectClass.getName(), ex); 183 } 184 } 185 } 186 } 187 return instance; 188 } 189 190 191 /** 192 * Create a new proxy according to the settings in this factory. 193 * <p>Can be called repeatedly. Effect will vary if we've added 194 * or removed interfaces. Can add and remove interceptors. 195 * <p>Uses a default class loader: Usually, the thread context class loader 196 * (if necessary for proxy creation). 197 * @return the new proxy 198 */ 199 @SuppressWarnings("unchecked") 200 public <T> T getProxy() { 201 return (T) createAopProxy().getProxy(); 202 } 203 204 /** 205 * Create a new proxy according to the settings in this factory. 206 * <p>Can be called repeatedly. Effect will vary if we've added 207 * or removed interfaces. Can add and remove interceptors. 208 * <p>Uses the given class loader (if necessary for proxy creation). 209 * @param classLoader the class loader to create the proxy with 210 * @return the new proxy 211 */ 212 @SuppressWarnings("unchecked") 213 public <T> T getProxy(ClassLoader classLoader) { 214 return (T) createAopProxy().getProxy(classLoader); 215 } 216 217}