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.io.Serializable;
020
021import org.springframework.beans.factory.BeanFactory;
022import org.springframework.beans.factory.config.ConfigurableBeanFactory;
023import org.springframework.core.Ordered;
024import org.springframework.core.annotation.OrderUtils;
025import org.springframework.lang.Nullable;
026import org.springframework.util.Assert;
027import org.springframework.util.ClassUtils;
028
029/**
030 * {@link org.springframework.aop.aspectj.AspectInstanceFactory} implementation
031 * backed by a Spring {@link org.springframework.beans.factory.BeanFactory}.
032 *
033 * <p>Note that this may instantiate multiple times if using a prototype,
034 * which probably won't give the semantics you expect.
035 * Use a {@link LazySingletonAspectInstanceFactoryDecorator}
036 * to wrap this to ensure only one new aspect comes back.
037 *
038 * @author Rod Johnson
039 * @author Juergen Hoeller
040 * @since 2.0
041 * @see org.springframework.beans.factory.BeanFactory
042 * @see LazySingletonAspectInstanceFactoryDecorator
043 */
044@SuppressWarnings("serial")
045public class BeanFactoryAspectInstanceFactory implements MetadataAwareAspectInstanceFactory, Serializable {
046
047        private final BeanFactory beanFactory;
048
049        private final String name;
050
051        private final AspectMetadata aspectMetadata;
052
053
054        /**
055         * Create a BeanFactoryAspectInstanceFactory. AspectJ will be called to
056         * introspect to create AJType metadata using the type returned for the
057         * given bean name from the BeanFactory.
058         * @param beanFactory the BeanFactory to obtain instance(s) from
059         * @param name the name of the bean
060         */
061        public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name) {
062                this(beanFactory, name, null);
063        }
064
065        /**
066         * Create a BeanFactoryAspectInstanceFactory, providing a type that AspectJ should
067         * introspect to create AJType metadata. Use if the BeanFactory may consider the type
068         * to be a subclass (as when using CGLIB), and the information should relate to a superclass.
069         * @param beanFactory the BeanFactory to obtain instance(s) from
070         * @param name the name of the bean
071         * @param type the type that should be introspected by AspectJ
072         * ({@code null} indicates resolution through {@link BeanFactory#getType} via the bean name)
073         */
074        public BeanFactoryAspectInstanceFactory(BeanFactory beanFactory, String name, @Nullable Class<?> type) {
075                Assert.notNull(beanFactory, "BeanFactory must not be null");
076                Assert.notNull(name, "Bean name must not be null");
077                this.beanFactory = beanFactory;
078                this.name = name;
079                Class<?> resolvedType = type;
080                if (type == null) {
081                        resolvedType = beanFactory.getType(name);
082                        Assert.notNull(resolvedType, "Unresolvable bean type - explicitly specify the aspect class");
083                }
084                this.aspectMetadata = new AspectMetadata(resolvedType, name);
085        }
086
087
088        @Override
089        public Object getAspectInstance() {
090                return this.beanFactory.getBean(this.name);
091        }
092
093        @Override
094        @Nullable
095        public ClassLoader getAspectClassLoader() {
096                return (this.beanFactory instanceof ConfigurableBeanFactory ?
097                                ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
098                                ClassUtils.getDefaultClassLoader());
099        }
100
101        @Override
102        public AspectMetadata getAspectMetadata() {
103                return this.aspectMetadata;
104        }
105
106        @Override
107        @Nullable
108        public Object getAspectCreationMutex() {
109                if (this.beanFactory.isSingleton(this.name)) {
110                        // Rely on singleton semantics provided by the factory -> no local lock.
111                        return null;
112                }
113                else if (this.beanFactory instanceof ConfigurableBeanFactory) {
114                        // No singleton guarantees from the factory -> let's lock locally but
115                        // reuse the factory's singleton lock, just in case a lazy dependency
116                        // of our advice bean happens to trigger the singleton lock implicitly...
117                        return ((ConfigurableBeanFactory) this.beanFactory).getSingletonMutex();
118                }
119                else {
120                        return this;
121                }
122        }
123
124        /**
125         * Determine the order for this factory's target aspect, either
126         * an instance-specific order expressed through implementing the
127         * {@link org.springframework.core.Ordered} interface (only
128         * checked for singleton beans), or an order expressed through the
129         * {@link org.springframework.core.annotation.Order} annotation
130         * at the class level.
131         * @see org.springframework.core.Ordered
132         * @see org.springframework.core.annotation.Order
133         */
134        @Override
135        public int getOrder() {
136                Class<?> type = this.beanFactory.getType(this.name);
137                if (type != null) {
138                        if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) {
139                                return ((Ordered) this.beanFactory.getBean(this.name)).getOrder();
140                        }
141                        return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE);
142                }
143                return Ordered.LOWEST_PRECEDENCE;
144        }
145
146
147        @Override
148        public String toString() {
149                return getClass().getSimpleName() + ": bean name '" + this.name + "'";
150        }
151
152}