- 一、引入依赖
- 二、定义一个注解
- 三、创建一个FactoryBean
- 四、创建一个BeanPostProcessor
- 4.1 其他关联类
- AnnotationUtils
- ServiceBeanNameBuilder
- 五、注入InstantiationAwareBeanPostProcessor到IoC中
- 5.1 实现ImportBeanDefinitionRegistrar接口
- 5.2 通过@Import注入
- 六、使用
- 6.1 打jar包
- 6.2 引用jar
- 6.3 调用
- 6.4 注入是否为单例测试
一、引入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.30</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.12.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
二、定义一个注解
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyReference {
}
三、创建一个FactoryBean
@Slf4j
public class MyFactoryBean<Service> implements FactoryBean<Service> {
/**
* 缓存
*/
private final ConcurrentMap<String, Service> factoryBeanCache = new ConcurrentHashMap<>(32);
private final Class<Service> serviceClass;
public MyFactoryBean(Class<Service> serviceClass) {
this.serviceClass = serviceClass;
}
public static <T> MyFactoryBean<T> of(Class<T> serviceClass) {
return new MyFactoryBean<>(serviceClass);
}
@Override
public Service getObject() throws Exception {
log.info("create my factoryBean, serviceClass={}", serviceClass.getName());
String key = getObjectType().getName();
Service bean = this.factoryBeanCache.get(key);
if (bean == null) {
synchronized (this.factoryBeanCache) {
bean = this.factoryBeanCache.get(key);
if (bean == null) {
// 创建对象
bean = createObject();
this.factoryBeanCache.put(key, bean);
}
}
}
return bean;
}
private Service createObject() {
return (Service) Proxy.newProxyInstance(this.getObjectType().getClassLoader(),
new Class[]{serviceClass},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("myFactoryBean proxy before, method name={}", method.getName());
log.info("myFactoryBean proxy after");
return null;
}
});
}
@Override
public Class<?> getObjectType() {
return this.serviceClass;
}
}
四、创建一个BeanPostProcessor
@Slf4j
public class ReferenceAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered,
BeanFactoryAware, EnvironmentAware, DisposableBean, ApplicationListener, ApplicationContextAware {
private static final int CACHE_SIZE = Integer.getInteger("", 32);
/**
* 需要扫描的注解集合
*/
private final Class<? extends Annotation>[] annotationTypes;
/**
* 是否以Spring IoC容器中Bean优先
* true:如果Spring IoC容器中存在,直接注入,多个注入第一个
*/
private final Boolean isSpringIoCBeanPreferred;
private final ConcurrentMap<String, AnnotatedInjectionMetadata> injectionMetadataCache =
new ConcurrentHashMap<String, AnnotatedInjectionMetadata>(CACHE_SIZE);
private final ConcurrentMap<String, MyFactoryBean<?>> injectedObjectsCache = new ConcurrentHashMap<>(CACHE_SIZE);
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private ApplicationContext applicationContext;
private int order = Ordered.LOWEST_PRECEDENCE - 3;
private boolean classValuesAsString = true;
private boolean nestedAnnotationsAsMap = true;
private boolean ignoreDefaultValue = true;
private boolean tryMergedAnnotation = true;
private static Map<String, TreeSet<String>> referencedBeanNameIdx = new HashMap<>();
private final ConcurrentMap<String, MyFactoryBean<?>> factoryBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
private final ConcurrentMap<InjectionMetadata.InjectedElement, MyFactoryBean<?>> injectedFieldMyFactoryBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
private final ConcurrentMap<InjectionMetadata.InjectedElement, MyFactoryBean<?>> injectedMethodMyFactoryBeanCache =
new ConcurrentHashMap<>(CACHE_SIZE);
public ReferenceAnnotationBeanPostProcessor(Class<? extends Annotation>[] annotationTypes) {
this(annotationTypes, true);
}
public ReferenceAnnotationBeanPostProcessor(Class<? extends Annotation>[] annotationTypes, Boolean isSpringIoCBeanPreferred) {
Assert.notEmpty(annotationTypes, "The argument of annotations' types must not empty");
Assert.notEmpty(annotationTypes, "The argument of isSpringIoCBeanPreferred must not empty");
this.annotationTypes = annotationTypes;
this.isSpringIoCBeanPreferred = isSpringIoCBeanPreferred;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds,
Object bean, String beanName) throws BeanCreationException {
// 查找注入元数据
InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
try {
// 注入
metadata.inject(bean, beanName, pvs);
} catch (BeanCreationException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + bean.getClass().getSimpleName()
+ " dependencies is failed", ex);
}
return pvs;
}
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
/**
* 执行的时间节点是bean刚刚初始化完 但在属性填充之前;
* spring会为每个beanDefinition依次调用实现了MergedBeanDefinitionPostProcessor接口的PostProcessor的改方法
*/
if (beanType == null) {
return;
}
// 查找注入元数据
InjectionMetadata metadata = this.findInjectionMetadata(beanName, beanType, (PropertyValues) null);
metadata.checkConfigMembers(beanDefinition);
}
/**
* 查找注入元数据
*
* @param beanName
* @param clazz
* @param pvs
* @return
*/
private InjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
String cacheKey = StringUtils.hasLength(beanName) ? beanName : clazz.getName();
AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
// double check
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
// build
metadata = this.buildAnnotatedMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError e) {
throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() + "] for annotation metadata: could not find class that it depends on", e);
}
}
}
}
return metadata;
}
private AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
// field
Collection<AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
// method
Collection<AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
return new AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
}
private List<AnnotatedMethodElement> findAnnotatedMethodMetadata(final Class<?> beanClass) {
final List<AnnotatedMethodElement> elements = new LinkedList<AnnotatedMethodElement>();
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Method bridgedMethod = findBridgedMethod(method);
if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
AnnotationAttributes attributes = doGetAnnotationAttributes(bridgedMethod, annotationType);
if (attributes != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
if (Modifier.isStatic(method.getModifiers())) {
if (log.isWarnEnabled()) {
log.warn("@" + annotationType.getName() + " annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterTypes().length == 0) {
if (log.isWarnEnabled()) {
log.warn("@" + annotationType.getName() + " annotation should only be used on methods with parameters: " +
method);
}
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
elements.add(new AnnotatedMethodElement(method, pd, attributes, applicationContext));
}
}
}
});
return elements;
}
protected AnnotationAttributes doGetAnnotationAttributes(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType) {
return AnnotationUtils.getAnnotationAttributes(annotatedElement, annotationType, this.environment,
classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, tryMergedAnnotation);
}
protected final Class<? extends Annotation>[] getAnnotationTypes() {
return annotationTypes;
}
private List<AnnotatedFieldElement> findFieldAnnotationMetadata(final Class<?> beanClass) {
final List<AnnotatedFieldElement> elements = new LinkedList<AnnotatedFieldElement>();
ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
AnnotationAttributes attributes = doGetAnnotationAttributes(field, annotationType);
if (attributes != null) {
// 非静态方法
if (Modifier.isStatic(field.getModifiers())) {
if (log.isWarnEnabled()) {
log.warn("@" + annotationType.getName() + " is not supported on static fields: " + field);
}
return;
}
elements.add(new AnnotatedFieldElement(field, attributes, applicationContext));
}
}
}
});
return elements;
}
@Override
public int getOrder() {
return this.order;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory,
"AnnotationInjectedBeanPostProcessor requires a ConfigurableListableBeanFactory");
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
@Override
public void destroy() throws Exception {
for (Object object : injectedObjectsCache.values()) {
if (log.isInfoEnabled()) {
log.info(object + " was destroying!");
}
if (object instanceof DisposableBean) {
((DisposableBean) object).destroy();
}
}
this.injectedObjectsCache.clear();
injectionMetadataCache.clear();
injectedObjectsCache.clear();
if (log.isInfoEnabled()) {
log.info(getClass() + " was destroying success!");
}
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
protected MyFactoryBean<?> getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
String cacheKey = this.buildInjectedObjectCacheKey(attributes, bean, beanName, injectedType, injectedElement);
MyFactoryBean<?> injectedObject = this.injectedObjectsCache.get(cacheKey);
if (injectedObject == null) {
synchronized (this.injectedObjectsCache) {
// double check
injectedObject = this.injectedObjectsCache.get(cacheKey);
if (injectedObject == null) {
// 获取需要注入的Bean
injectedObject = this.doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
this.injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
}
}
}
return injectedObject;
}
protected MyFactoryBean<?> doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception {
log.info("doGetInjectedBean bean={}, beanName={}", bean.getClass().getName(), beanName);
// String referencedBeanName = buildReferencedBeanName(attributes, injectedType);
/**
* The name of bean that is declared by {@link Reference @MyReference} annotation injection
*/
String factoryBeanName = getMyFactoryBeanName(attributes, injectedType);
referencedBeanNameIdx.computeIfAbsent(factoryBeanName, k -> new TreeSet<String>()).add(factoryBeanName);
MyFactoryBean<?> factoryBean = buildMyFactoryBeanIfAbsent(factoryBeanName, attributes, injectedType);
if (!isSpringIoCBeanPreferred) {
// 注入 Bean 到spring IoC 中
registerMyFactoryBean(factoryBean, factoryBeanName);
}
// 缓存
cacheInjectedReferenceBean(factoryBean, injectedElement);
// 执行初始化后应用Bean后处理器
return (MyFactoryBean<?>) getBeanFactory().applyBeanPostProcessorsAfterInitialization(factoryBean, factoryBeanName);
}
private void cacheInjectedReferenceBean(MyFactoryBean<?> factoryBean,
InjectionMetadata.InjectedElement injectedElement) {
if (injectedElement.getMember() instanceof Field) {
injectedFieldMyFactoryBeanCache.put(injectedElement, factoryBean);
} else if (injectedElement.getMember() instanceof Method) {
injectedMethodMyFactoryBeanCache.put(injectedElement, factoryBean);
}
}
private void registerMyFactoryBean(MyFactoryBean<?> factoryBean, String beanName) {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsBean(beanName)) {
Object bean = beanFactory.getBean(beanName);
if (!Objects.equals(bean.getClass().getName(), factoryBean.getObjectType().getName())) {
throw new RuntimeException("bean name '" + beanName + "' is exists in the container");
}
} else {
beanFactory.registerSingleton(beanName, factoryBean);
}
}
protected ConfigurableListableBeanFactory getBeanFactory() {
return beanFactory;
}
private MyFactoryBean<?> buildMyFactoryBeanIfAbsent(String referenceBeanName, AnnotationAttributes attributes,
Class<?> referencedType) throws Exception {
MyFactoryBean<?> factoryBean = factoryBeanCache.get(referenceBeanName);
if (factoryBean == null) {
factoryBean = MyFactoryBean.of(referencedType);
factoryBeanCache.putIfAbsent(referenceBeanName, factoryBean);
}
return factoryBeanCache.get(referenceBeanName);
}
private String getMyFactoryBeanName(AnnotationAttributes attributes, Class<?> interfaceClass) {
String beanName = AnnotationUtils.getAttribute(attributes, "id");
if (!hasText(beanName)) {
beanName = generateMyFactoryBeanName(attributes, interfaceClass);
}
return beanName;
}
private String generateMyFactoryBeanName(AnnotationAttributes attributes, Class<?> interfaceClass) {
StringBuilder beanNameBuilder = new StringBuilder("@MyReference");
if (!attributes.isEmpty()) {
beanNameBuilder.append('(');
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
String value;
if ("parameters".equals(entry.getKey())) {
ArrayList<String> pairs = getParameterPairs(entry);
value = convertAttribute(pairs.stream().sorted().toArray());
} else {
value = convertAttribute(entry.getValue());
}
beanNameBuilder.append(entry.getKey())
.append('=')
.append(value)
.append(',');
}
// replace the latest "," to be ")"
beanNameBuilder.setCharAt(beanNameBuilder.lastIndexOf(","), ')');
}
beanNameBuilder.append(" ").append(interfaceClass.getName());
return beanNameBuilder.toString();
}
private String convertAttribute(Object obj) {
if (obj == null) {
return null;
}
if (obj instanceof Annotation) {
AnnotationAttributes attributes = AnnotationUtils.getAnnotationAttributes((Annotation) obj, true);
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
entry.setValue(convertAttribute(entry.getValue()));
}
return String.valueOf(attributes);
} else if (obj.getClass().isArray()) {
Object[] array = ObjectUtils.toObjectArray(obj);
String[] newArray = new String[array.length];
for (int i = 0; i < array.length; i++) {
newArray[i] = convertAttribute(array[i]);
}
return Arrays.toString(Arrays.stream(newArray).sorted().toArray());
} else {
return String.valueOf(obj);
}
}
private ArrayList<String> getParameterPairs(Map.Entry<String, Object> entry) {
String[] entryValues = (String[]) entry.getValue();
ArrayList<String> pairs = new ArrayList<>();
// parameters spec is {key1,value1,key2,value2}
for (int i = 0; i < entryValues.length / 2 * 2; i = i + 2) {
pairs.add(entryValues[i] + "=" + entryValues[i + 1]);
}
return pairs;
}
protected String buildInjectedObjectCacheKey(AnnotationAttributes attributes, Object bean, String beanName,
Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) {
return buildReferencedBeanName(attributes, injectedType) +
"#source=" + (injectedElement.getMember()) +
"#attributes=" + AnnotationUtils.getAttributes(attributes, getEnvironment());
}
private String buildReferencedBeanName(AnnotationAttributes attributes, Class<?> serviceInterfaceType) {
ServiceBeanNameBuilder serviceBeanNameBuilder = create(attributes, serviceInterfaceType, getEnvironment());
return serviceBeanNameBuilder.build();
}
public static ServiceBeanNameBuilder create(AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {
return new ServiceBeanNameBuilder(attributes, defaultInterfaceClass, environment);
}
private static <T> Collection<T> combine(Collection<? extends T>... elements) {
List<T> allElements = new ArrayList<T>();
for (Collection<? extends T> e : elements) {
allElements.addAll(e);
}
return allElements;
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
referencedBeanNameIdx.entrySet().stream().filter(e -> e.getValue().size() > 1).forEach(e -> {
String logPrefix = e.getKey() + " has " + e.getValue().size() + " reference instances, there are: ";
log.warn(e.getValue().stream().collect(Collectors.joining(", ", logPrefix, "")));
});
referencedBeanNameIdx.clear();
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
private class AnnotatedInjectionMetadata extends InjectionMetadata {
private final Collection<AnnotatedFieldElement> fieldElements;
private final Collection<AnnotatedMethodElement> methodElements;
public AnnotatedInjectionMetadata(Class<?> targetClass, Collection<AnnotatedFieldElement> fieldElements, Collection<AnnotatedMethodElement> methodElements) {
super(targetClass, ReferenceAnnotationBeanPostProcessor.combine(fieldElements, methodElements));
this.fieldElements = fieldElements;
this.methodElements = methodElements;
}
public Collection<AnnotatedFieldElement> getFieldElements() {
return this.fieldElements;
}
public Collection<AnnotatedMethodElement> getMethodElements() {
return this.methodElements;
}
}
public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement {
private final Field field;
private final AnnotationAttributes attributes;
private volatile Object bean;
private ApplicationContext applicationContext;
protected AnnotatedFieldElement(Field field, AnnotationAttributes attributes, ApplicationContext applicationContext) {
super(field, (PropertyDescriptor) null);
this.field = field;
this.attributes = attributes;
this.applicationContext = applicationContext;
}
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> injectedType = this.resolveInjectedType(bean, this.field);
ReflectionUtils.makeAccessible(this.field);
MyFactoryBean<?> injectedObject = getInjectedObject(this.attributes, bean, beanName, injectedType, this);
String factoryBeanName = getMyFactoryBeanName(attributes, injectedType);
// 注入
this.field.set(bean, getFinallyInjectedBean(injectedObject, factoryBeanName));
}
private Class<?> resolveInjectedType(Object bean, Field field) {
Type genericType = field.getGenericType();
return genericType instanceof Class ? field.getType() : GenericTypeResolver.resolveTypeArgument(AopUtils.getTargetClass(bean), field.getDeclaringClass());
}
}
private class AnnotatedMethodElement extends InjectionMetadata.InjectedElement {
private final Method method;
private final AnnotationAttributes attributes;
private volatile Object object;
private ApplicationContext applicationContext;
protected AnnotatedMethodElement(Method method, PropertyDescriptor pd, AnnotationAttributes attributes, ApplicationContext applicationContext) {
super(method, pd);
this.method = method;
this.attributes = attributes;
this.applicationContext = applicationContext;
}
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
Class<?> injectedType = this.pd.getPropertyType();
// 获取需要注入的Bean
MyFactoryBean<?> injectedObject = ReferenceAnnotationBeanPostProcessor.this.getInjectedObject(this.attributes, bean, beanName, injectedType, this);
ReflectionUtils.makeAccessible(this.method);
String factoryBeanName = getMyFactoryBeanName(attributes, injectedType);
// 注入
this.method.invoke(bean, getFinallyInjectedBean(injectedObject, factoryBeanName));
}
}
/**
* 获取最终需要注入的Bean
*
* @param factoryBean
* @param beanName
* @return
* @throws Exception
*/
private Object getFinallyInjectedBean(MyFactoryBean<?> factoryBean, String beanName) throws Exception {
if (!isSpringIoCBeanPreferred) {
return factoryBean.getObject();
}
Object injected = null;
String[] beanNames = this.applicationContext.getBeanNamesForType(factoryBean.getObjectType());
if (beanNames.length >= 1) {
// find first
injected = this.applicationContext.getBean(beanNames[0]);
}
if (injected == null) {
injected = factoryBean.getObject();
// 注入到spring Ioc容器中
registerMyFactoryBean(factoryBean, beanName);
}
return injected;
}
public Environment getEnvironment() {
return this.environment;
}
}
4.1 其他关联类
AnnotationUtils
public class AnnotationUtils {
public static final String ANNOTATED_ELEMENT_UTILS_CLASS_NAME = "org.springframework.core.annotation.AnnotatedElementUtils";
public static <T> T getAttribute(Map<String, Object> attributes, String attributeName) {
return getAttribute(attributes, attributeName, false);
}
public static <T> T getAttribute(Map<String, Object> attributes, String attributeName, boolean required) {
T value = getAttribute(attributes, attributeName, null);
if (required && value == null) {
throw new IllegalStateException("The attribute['" + attributeName + "] is required!");
}
return value;
}
public static <T> T getAttribute(Map<String, Object> attributes, String attributeName, T defaultValue) {
T value = (T) attributes.get(attributeName);
return value == null ? defaultValue : value;
}
public static String resolveInterfaceName(AnnotationAttributes attributes, Class<?> defaultInterfaceClass) {
Boolean generic = getAttribute(attributes, "generic");
if (generic != null && generic) {
// it's a generic reference
String interfaceClassName = getAttribute(attributes, "interfaceName");
Assert.hasText(interfaceClassName,
"@Reference interfaceName() must be present when reference a generic service!");
return interfaceClassName;
}
return resolveServiceInterfaceClass(attributes, defaultInterfaceClass).getName();
}
public static Class<?> resolveServiceInterfaceClass(AnnotationAttributes attributes, Class<?> defaultInterfaceClass)
throws IllegalArgumentException {
ClassLoader classLoader = defaultInterfaceClass != null ? defaultInterfaceClass.getClassLoader() : Thread.currentThread().getContextClassLoader();
Class<?> interfaceClass = getAttribute(attributes, "interfaceClass");
if (void.class.equals(interfaceClass)) { // default or set void.class for purpose.
interfaceClass = null;
String interfaceClassName = getAttribute(attributes, "interfaceName");
if (hasText(interfaceClassName)) {
if (ClassUtils.isPresent(interfaceClassName, classLoader)) {
interfaceClass = resolveClassName(interfaceClassName, classLoader);
}
}
}
if (interfaceClass == null && defaultInterfaceClass != null) {
// Find all interfaces from the annotated class
Class<?>[] allInterfaces = getAllInterfacesForClass(defaultInterfaceClass);
if (allInterfaces.length > 0) {
interfaceClass = allInterfaces[0];
}
}
return interfaceClass == null ? defaultInterfaceClass : interfaceClass;
}
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType,
PropertyResolver propertyResolver,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap,
boolean ignoreDefaultValue,
boolean tryMergedAnnotation,
String... ignoreAttributeNames) {
AnnotationAttributes attributes = null;
if (tryMergedAnnotation) {
attributes = tryGetMergedAnnotationAttributes(annotatedElement, annotationType, propertyResolver,
classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
}
if (attributes == null) {
attributes = getAnnotationAttributes(annotatedElement, annotationType, propertyResolver,
classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
}
return attributes;
}
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType,
PropertyResolver propertyResolver,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap,
boolean ignoreDefaultValue,
String... ignoreAttributeNames) {
Annotation annotation = annotatedElement.getAnnotation(annotationType);
return annotation == null ? null : getAnnotationAttributes(annotation, propertyResolver,
classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
}
public static Annotation tryGetMergedAnnotation(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap) {
Annotation mergedAnnotation = null;
ClassLoader classLoader = annotationType.getClassLoader();
if (ClassUtils.isPresent(ANNOTATED_ELEMENT_UTILS_CLASS_NAME, classLoader)) {
Class<?> annotatedElementUtilsClass = resolveClassName(ANNOTATED_ELEMENT_UTILS_CLASS_NAME, classLoader);
// getMergedAnnotation method appears in the Spring Framework 4.2
Method getMergedAnnotationMethod = findMethod(annotatedElementUtilsClass, "getMergedAnnotation",
AnnotatedElement.class, Class.class, boolean.class, boolean.class);
if (getMergedAnnotationMethod != null) {
mergedAnnotation = (Annotation) invokeMethod(getMergedAnnotationMethod, null,
annotatedElement, annotationType, classValuesAsString, nestedAnnotationsAsMap);
}
}
return mergedAnnotation;
}
public static AnnotationAttributes tryGetMergedAnnotationAttributes(AnnotatedElement annotatedElement,
Class<? extends Annotation> annotationType,
PropertyResolver propertyResolver,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap,
boolean ignoreDefaultValue,
String... ignoreAttributeNames) {
Annotation annotation = tryGetMergedAnnotation(annotatedElement, annotationType, classValuesAsString, nestedAnnotationsAsMap);
return annotation == null ? null : getAnnotationAttributes(annotation, propertyResolver,
classValuesAsString, nestedAnnotationsAsMap, ignoreDefaultValue, ignoreAttributeNames);
}
public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, boolean ignoreDefaultValue,
String... ignoreAttributeNames) {
return getAnnotationAttributes(annotation, null, ignoreDefaultValue, ignoreAttributeNames);
}
public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, PropertyResolver propertyResolver,
boolean ignoreDefaultValue, String... ignoreAttributeNames) {
return getAnnotationAttributes(annotation, propertyResolver, false, false, ignoreDefaultValue, ignoreAttributeNames);
}
public static AnnotationAttributes getAnnotationAttributes(Annotation annotation,
PropertyResolver propertyResolver,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap,
boolean ignoreDefaultValue,
String... ignoreAttributeNames) {
return fromMap(getAttributes(annotation, propertyResolver, classValuesAsString, nestedAnnotationsAsMap,
ignoreDefaultValue, ignoreAttributeNames));
}
public static Map<String, Object> getAttributes(Annotation annotation,
PropertyResolver propertyResolver,
boolean classValuesAsString,
boolean nestedAnnotationsAsMap,
boolean ignoreDefaultValue,
String... ignoreAttributeNames) {
Map<String, Object> annotationAttributes = org.springframework.core.annotation.AnnotationUtils.getAnnotationAttributes(annotation, classValuesAsString, nestedAnnotationsAsMap);
String[] actualIgnoreAttributeNames = ignoreAttributeNames;
if (ignoreDefaultValue && !isEmpty(annotationAttributes)) {
List<String> attributeNamesToIgnore = new LinkedList<String>(asList(ignoreAttributeNames));
for (Map.Entry<String, Object> annotationAttribute : annotationAttributes.entrySet()) {
String attributeName = annotationAttribute.getKey();
Object attributeValue = annotationAttribute.getValue();
if (nullSafeEquals(attributeValue, getDefaultValue(annotation, attributeName))) {
attributeNamesToIgnore.add(attributeName);
}
}
// extends the ignored list
actualIgnoreAttributeNames = attributeNamesToIgnore.toArray(new String[attributeNamesToIgnore.size()]);
}
return getAttributes(annotationAttributes, propertyResolver, actualIgnoreAttributeNames);
}
public static Map<String, Object> getAttributes(Map<String, Object> annotationAttributes,
PropertyResolver propertyResolver, String... ignoreAttributeNames) {
Set<String> ignoreAttributeNamesSet = new HashSet<String>();
if (ignoreAttributeNames != null && ignoreAttributeNames.length > 0) {
for (String ignoreAttributeName : ignoreAttributeNames) {
ignoreAttributeNamesSet.add(ignoreAttributeName);
}
}
Map<String, Object> actualAttributes = new LinkedHashMap<String, Object>();
for (Map.Entry<String, Object> annotationAttribute : annotationAttributes.entrySet()) {
String attributeName = annotationAttribute.getKey();
Object attributeValue = annotationAttribute.getValue();
// ignore attribute name
if (ignoreAttributeNamesSet.contains(attributeName)) {
continue;
}
if (attributeValue instanceof String) {
attributeValue = resolvePlaceholders(valueOf(attributeValue), propertyResolver);
} else if (attributeValue instanceof String[]) {
String[] values = (String[]) attributeValue;
for (int i = 0; i < values.length; i++) {
values[i] = resolvePlaceholders(values[i], propertyResolver);
}
attributeValue = values;
}
actualAttributes.put(attributeName, attributeValue);
}
return actualAttributes;
}
private static String resolvePlaceholders(String attributeValue, PropertyResolver propertyResolver) {
String resolvedValue = attributeValue;
if (propertyResolver != null) {
resolvedValue = propertyResolver.resolvePlaceholders(resolvedValue);
resolvedValue = trimWhitespace(resolvedValue);
}
return resolvedValue;
}
}
ServiceBeanNameBuilder
public class ServiceBeanNameBuilder {
private static final String SEPARATOR = ":";
// Required
private final String interfaceClassName;
private final Environment environment;
// Optional
private String version;
private String group;
private ServiceBeanNameBuilder(Class<?> interfaceClass, Environment environment) {
this(interfaceClass.getName(), environment);
}
private ServiceBeanNameBuilder(String interfaceClassName, Environment environment) {
this.interfaceClassName = interfaceClassName;
this.environment = environment;
}
public ServiceBeanNameBuilder(AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {
this(AnnotationUtils.resolveInterfaceName(attributes, defaultInterfaceClass), environment);
this.group(AnnotationUtils.getAttribute(attributes, "group"));
this.version(AnnotationUtils.getAttribute(attributes, "version"));
}
public static ServiceBeanNameBuilder create(AnnotationAttributes attributes, Class<?> defaultInterfaceClass, Environment environment) {
return new ServiceBeanNameBuilder(attributes, defaultInterfaceClass, environment);
}
public static ServiceBeanNameBuilder create(Class<?> interfaceClass, Environment environment) {
return new ServiceBeanNameBuilder(interfaceClass, environment);
}
private static void append(StringBuilder builder, String value) {
if (StringUtils.hasText(value)) {
builder.append(SEPARATOR).append(value);
}
}
public ServiceBeanNameBuilder group(String group) {
this.group = group;
return this;
}
public ServiceBeanNameBuilder version(String version) {
this.version = version;
return this;
}
public String build() {
StringBuilder beanNameBuilder = new StringBuilder("ServiceBean");
// Required
append(beanNameBuilder, interfaceClassName);
// Optional
append(beanNameBuilder, version);
append(beanNameBuilder, group);
// Build and remove last ":"
String rawBeanName = beanNameBuilder.toString();
// Resolve placeholders
return environment.resolvePlaceholders(rawBeanName);
}
}
五、注入InstantiationAwareBeanPostProcessor到IoC中
5.1 实现ImportBeanDefinitionRegistrar接口
public class RefImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(ReferenceAnnotationBeanPostProcessor.class);
ConstructorArgumentValues values = new ConstructorArgumentValues();
// 添加需要扫描的注解
values.addIndexedArgumentValue(0, new Class[]{MyReference.class});
// isSpringIoCBeanPreferred:是否以Spring IoC容器中Bean优先
values.addIndexedArgumentValue(1, true);
beanDefinition.setConstructorArgumentValues(values);
String beanName = importBeanNameGenerator.generateBeanName(beanDefinition, registry);
registry.registerBeanDefinition(beanName, beanDefinition);
}
}
5.2 通过@Import注入
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({RefImportBeanDefinitionRegistrar.class})
public @interface EnableReference {
}
六、使用
6.1 打jar包
将上面代码打成一个jar
6.2 引用jar
<dependency>
<groupId>com.tortoise</groupId>
<artifactId>my-reference</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
6.3 调用
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e20037a5b60c4b66a6dcc47f606c86f0.png