001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.aop.aspectj.annotation;
018:
019: import java.util.ArrayList;
020: import java.util.List;
021: import java.util.regex.Pattern;
022:
023: import org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator;
024: import org.springframework.beans.factory.ListableBeanFactory;
025: import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
026: import org.springframework.util.Assert;
027:
028: /**
029: * {@link AspectJAwareAdvisorAutoProxyCreator} subclass that processes all AspectJ
030: * annotation aspects in the current application context, as well as Spring Advisors.
031: *
032: * <p>Any AspectJ annotated classes will automatically be recognized, and their
033: * advice applied if Spring AOP's proxy-based model is capable of applying it.
034: * This covers method execution joinpoints.
035: *
036: * <p>If the <aop:include> element is used, only @AspectJ beans with names matched by
037: * an include pattern will be considered as defining aspects to use for Spring auto-proxying.
038: *
039: * <p>Processing of Spring Advisors follows the rules established in
040: * {@link org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator}.
041: *
042: * @author Rod Johnson
043: * @author Juergen Hoeller
044: * @since 2.0
045: * @see org.springframework.aop.aspectj.annotation.AspectJAdvisorFactory
046: */
047: public class AnnotationAwareAspectJAutoProxyCreator extends
048: AspectJAwareAdvisorAutoProxyCreator {
049:
050: private List<Pattern> includePatterns;
051:
052: private AspectJAdvisorFactory aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory();
053:
054: private BeanFactoryAspectJAdvisorsBuilder aspectJAdvisorsBuilder;
055:
056: /**
057: * Set a list of regex patterns, matching eligible @AspectJ bean names.
058: * <p>Default is to consider all @AspectJ beans as eligible.
059: */
060: public void setIncludePatterns(List<String> patterns) {
061: this .includePatterns = new ArrayList<Pattern>(patterns.size());
062: for (String patternText : patterns) {
063: this .includePatterns.add(Pattern.compile(patternText));
064: }
065: }
066:
067: public void setAspectJAdvisorFactory(
068: AspectJAdvisorFactory aspectJAdvisorFactory) {
069: Assert.notNull(this .aspectJAdvisorFactory,
070: "AspectJAdvisorFactory must not be null");
071: this .aspectJAdvisorFactory = aspectJAdvisorFactory;
072: }
073:
074: @Override
075: protected void initBeanFactory(
076: ConfigurableListableBeanFactory beanFactory) {
077: super .initBeanFactory(beanFactory);
078: this .aspectJAdvisorsBuilder = new BeanFactoryAspectJAdvisorsBuilderAdapter(
079: beanFactory, this .aspectJAdvisorFactory);
080: }
081:
082: @Override
083: protected List findCandidateAdvisors() {
084: // Add all the Spring advisors found according to superclass rules.
085: List advisors = super .findCandidateAdvisors();
086: // Build Advisors for all AspectJ aspects in the bean factory.
087: advisors.addAll(this .aspectJAdvisorsBuilder
088: .buildAspectJAdvisors());
089: return advisors;
090: }
091:
092: protected boolean isInfrastructureClass(Class beanClass) {
093: // Previously we setProxyTargetClass(true) in the constructor, but that has too
094: // broad an impact. Instead we now override isInfrastructureClass to avoid proxying
095: // aspects. I'm not entirely happy with that as there is no good reason not
096: // to advise aspects, except that it causes advice invocation to go through a
097: // proxy, and if the aspect implements e.g the Ordered interface it will be
098: // proxied by that interface and fail at runtime as the advice method is not
099: // defined on the interface. We could potentially relax the restriction about
100: // not advising aspects in the future.
101: return (super .isInfrastructureClass(beanClass) || this .aspectJAdvisorFactory
102: .isAspect(beanClass));
103: }
104:
105: /**
106: * Check whether the given aspect bean is eligible for auto-proxying.
107: * <p>If no <aop:include> elements were used then "includePatterns" will be
108: * <code>null</code> and all beans are included. If "includePatterns" is non-null,
109: * then one of the patterns must match.
110: */
111: protected boolean isEligibleAspectBean(String beanName) {
112: if (this .includePatterns == null) {
113: return true;
114: } else {
115: for (Pattern pattern : this .includePatterns) {
116: if (pattern.matcher(beanName).matches()) {
117: return true;
118: }
119: }
120: return false;
121: }
122: }
123:
124: /**
125: * Subclass of BeanFactoryAspectJAdvisorsBuilderAdapter that delegates to
126: * surrounding AnnotationAwareAspectJAutoProxyCreator facilities.
127: */
128: private class BeanFactoryAspectJAdvisorsBuilderAdapter extends
129: BeanFactoryAspectJAdvisorsBuilder {
130:
131: public BeanFactoryAspectJAdvisorsBuilderAdapter(
132: ListableBeanFactory beanFactory,
133: AspectJAdvisorFactory advisorFactory) {
134: super (beanFactory, advisorFactory);
135: }
136:
137: protected boolean isEligibleBean(String beanName) {
138: return AnnotationAwareAspectJAutoProxyCreator.this
139: .isEligibleAspectBean(beanName);
140: }
141: }
142:
143: }
|