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.framework.autoproxy; 018 019import org.springframework.beans.factory.config.AutowireCapableBeanFactory; 020import org.springframework.beans.factory.config.BeanDefinition; 021import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 022import org.springframework.core.Conventions; 023import org.springframework.lang.Nullable; 024import org.springframework.util.StringUtils; 025 026/** 027 * Utilities for auto-proxy aware components. 028 * Mainly for internal use within the framework. 029 * 030 * @author Juergen Hoeller 031 * @since 2.0.3 032 * @see AbstractAutoProxyCreator 033 */ 034public abstract class AutoProxyUtils { 035 036 /** 037 * Bean definition attribute that may indicate whether a given bean is supposed 038 * to be proxied with its target class (in case of it getting proxied in the first 039 * place). The value is {@code Boolean.TRUE} or {@code Boolean.FALSE}. 040 * <p>Proxy factories can set this attribute if they built a target class proxy 041 * for a specific bean, and want to enforce that bean can always be cast 042 * to its target class (even if AOP advices get applied through auto-proxying). 043 * @see #shouldProxyTargetClass 044 */ 045 public static final String PRESERVE_TARGET_CLASS_ATTRIBUTE = 046 Conventions.getQualifiedAttributeName(AutoProxyUtils.class, "preserveTargetClass"); 047 048 /** 049 * Bean definition attribute that indicates the original target class of an 050 * auto-proxied bean, e.g. to be used for the introspection of annotations 051 * on the target class behind an interface-based proxy. 052 * @since 4.2.3 053 * @see #determineTargetClass 054 */ 055 public static final String ORIGINAL_TARGET_CLASS_ATTRIBUTE = 056 Conventions.getQualifiedAttributeName(AutoProxyUtils.class, "originalTargetClass"); 057 058 059 /** 060 * Determine whether the given bean should be proxied with its target 061 * class rather than its interfaces. Checks the 062 * {@link #PRESERVE_TARGET_CLASS_ATTRIBUTE "preserveTargetClass" attribute} 063 * of the corresponding bean definition. 064 * @param beanFactory the containing ConfigurableListableBeanFactory 065 * @param beanName the name of the bean 066 * @return whether the given bean should be proxied with its target class 067 */ 068 public static boolean shouldProxyTargetClass( 069 ConfigurableListableBeanFactory beanFactory, @Nullable String beanName) { 070 071 if (beanName != null && beanFactory.containsBeanDefinition(beanName)) { 072 BeanDefinition bd = beanFactory.getBeanDefinition(beanName); 073 return Boolean.TRUE.equals(bd.getAttribute(PRESERVE_TARGET_CLASS_ATTRIBUTE)); 074 } 075 return false; 076 } 077 078 /** 079 * Determine the original target class for the specified bean, if possible, 080 * otherwise falling back to a regular {@code getType} lookup. 081 * @param beanFactory the containing ConfigurableListableBeanFactory 082 * @param beanName the name of the bean 083 * @return the original target class as stored in the bean definition, if any 084 * @since 4.2.3 085 * @see org.springframework.beans.factory.BeanFactory#getType(String) 086 */ 087 @Nullable 088 public static Class<?> determineTargetClass( 089 ConfigurableListableBeanFactory beanFactory, @Nullable String beanName) { 090 091 if (beanName == null) { 092 return null; 093 } 094 if (beanFactory.containsBeanDefinition(beanName)) { 095 BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName); 096 Class<?> targetClass = (Class<?>) bd.getAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE); 097 if (targetClass != null) { 098 return targetClass; 099 } 100 } 101 return beanFactory.getType(beanName); 102 } 103 104 /** 105 * Expose the given target class for the specified bean, if possible. 106 * @param beanFactory the containing ConfigurableListableBeanFactory 107 * @param beanName the name of the bean 108 * @param targetClass the corresponding target class 109 * @since 4.2.3 110 */ 111 static void exposeTargetClass( 112 ConfigurableListableBeanFactory beanFactory, @Nullable String beanName, Class<?> targetClass) { 113 114 if (beanName != null && beanFactory.containsBeanDefinition(beanName)) { 115 beanFactory.getMergedBeanDefinition(beanName).setAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE, targetClass); 116 } 117 } 118 119 /** 120 * Determine whether the given bean name indicates an "original instance" 121 * according to {@link AutowireCapableBeanFactory#ORIGINAL_INSTANCE_SUFFIX}, 122 * skipping any proxy attempts for it. 123 * @param beanName the name of the bean 124 * @param beanClass the corresponding bean class 125 * @since 5.1 126 * @see AutowireCapableBeanFactory#ORIGINAL_INSTANCE_SUFFIX 127 */ 128 static boolean isOriginalInstance(String beanName, Class<?> beanClass) { 129 if (!StringUtils.hasLength(beanName) || beanName.length() != 130 beanClass.getName().length() + AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX.length()) { 131 return false; 132 } 133 return (beanName.startsWith(beanClass.getName()) && 134 beanName.endsWith(AutowireCapableBeanFactory.ORIGINAL_INSTANCE_SUFFIX)); 135 } 136 137}