DynamicMethodAnnotationBeanPostProcessor.java 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package cn.nosum.support.processor;
  2. import cn.nosum.support.annotation.DynamicClass;
  3. import cn.nosum.support.annotation.DynamicMethod;
  4. import cn.nosum.support.config.DynamicMethodsEndpointRegistrar;
  5. import cn.nosum.support.endpoint.DynamicMethodWrapper;
  6. import cn.nosum.support.endpoint.MethodEndpoint;
  7. import org.apache.commons.logging.Log;
  8. import org.apache.commons.logging.LogFactory;
  9. import org.springframework.aop.framework.Advised;
  10. import org.springframework.aop.support.AopUtils;
  11. import org.springframework.beans.BeansException;
  12. import org.springframework.beans.factory.config.BeanPostProcessor;
  13. import org.springframework.core.MethodIntrospector;
  14. import org.springframework.core.Ordered;
  15. import org.springframework.core.annotation.AnnotatedElementUtils;
  16. import org.springframework.core.annotation.AnnotationUtils;
  17. import org.springframework.util.ReflectionUtils;
  18. import java.lang.reflect.Method;
  19. import java.util.*;
  20. import java.util.concurrent.ConcurrentHashMap;
  21. import java.util.stream.Collectors;
  22. /**
  23. * Bean post-processor that registers methods annotated with {@link DynamicMethod}.
  24. *
  25. * @author Young
  26. */
  27. public class DynamicMethodAnnotationBeanPostProcessor implements BeanPostProcessor, Ordered {
  28. private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
  29. private final Log logger = LogFactory.getLog(getClass());
  30. @Override
  31. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  32. return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
  33. }
  34. @Override
  35. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  36. if (this.nonAnnotatedClasses.contains(bean.getClass())) {
  37. return bean;
  38. }
  39. Class<?> targetClass = AopUtils.getTargetClass(bean);
  40. Collection<DynamicClass> classLevelDynamicMethods = findConsumerClass(targetClass);
  41. if (classLevelDynamicMethods.isEmpty()){
  42. return bean;
  43. }
  44. Map<Method, Set<DynamicMethod>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
  45. (MethodIntrospector.MetadataLookup<Set<DynamicMethod>>) method -> {
  46. Set<DynamicMethod> listenerMethods = findConsumerClass(method);
  47. return (!listenerMethods.isEmpty() ? listenerMethods : null);
  48. });
  49. Set<Method> allMethods = Arrays.stream(bean.getClass().getDeclaredMethods()).filter(method-> !annotatedMethods.containsKey(method)).collect(Collectors.toSet());
  50. if (allMethods.isEmpty() && annotatedMethods.isEmpty()) {
  51. this.nonAnnotatedClasses.add(bean.getClass());
  52. if (this.logger.isTraceEnabled()) {
  53. this.logger.trace("No @DynamicMethod annotations found on bean type: " + bean.getClass());
  54. }
  55. } else {
  56. // Non-empty set of methods
  57. for (Map.Entry<Method, Set<DynamicMethod>> entry : annotatedMethods.entrySet()) {
  58. Method method = entry.getKey();
  59. for (DynamicMethod dynamicMethod : entry.getValue()) {
  60. processDynamicMethod(DynamicMethodWrapper.builder().name(dynamicMethod.name()).build(), method, bean, beanName);
  61. }
  62. }
  63. // empty set of methods
  64. for (Method method : allMethods) {
  65. processDynamicMethod(DynamicMethodWrapper.builder().name(method.getName()).build(), method, bean, beanName);
  66. }
  67. if (this.logger.isDebugEnabled()) {
  68. this.logger.debug(annotatedMethods.size() + " @DynamicMethod methods processed on bean '"
  69. + beanName + "': " + annotatedMethods);
  70. }
  71. }
  72. return bean;
  73. }
  74. protected void processDynamicMethod(DynamicMethodWrapper dynamicMethod, Method method, Object bean, String beanName) {
  75. Method methodToUse = checkProxy(method, bean);
  76. MethodEndpoint endpoint = new MethodEndpoint();
  77. endpoint.setBean(bean);
  78. endpoint.setMethod(method);
  79. processMethod(endpoint, dynamicMethod, bean, methodToUse, beanName);
  80. }
  81. protected void processMethod(MethodEndpoint endpoint,
  82. DynamicMethodWrapper dynamicMethod, Object bean, Object adminTarget, String beanName) {
  83. endpoint.setBeanName(beanName);
  84. DynamicMethodsEndpointRegistrar.registerEndpoint(endpoint,dynamicMethod);
  85. }
  86. /**
  87. * 检查代理对象
  88. *
  89. * @param methodArg 方法
  90. * @param bean Bean 实例
  91. * @return 如果目标类已经被代理,则检查注解是否存在于类本身
  92. */
  93. private Method checkProxy(Method methodArg, Object bean) {
  94. Method method = methodArg;
  95. if (AopUtils.isJdkDynamicProxy(bean)) {
  96. try {
  97. method = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
  98. Class<?>[] proxiedInterfaces = ((Advised) bean).getProxiedInterfaces();
  99. for (Class<?> iface : proxiedInterfaces) {
  100. try {
  101. method = iface.getMethod(method.getName(), method.getParameterTypes());
  102. break;
  103. } catch (NoSuchMethodException ignored) {
  104. }
  105. }
  106. } catch (SecurityException ex) {
  107. ReflectionUtils.handleReflectionException(ex);
  108. } catch (NoSuchMethodException ex) {
  109. throw new IllegalStateException(String.format(
  110. "@DynamicMethod method '%s' found on bean target class '%s', " +
  111. "but not found in any interface(s) for bean JDK proxy. Either " +
  112. "pull the method up to an interface or switch to subclass (CGLIB) " +
  113. "proxies by setting proxy-target-class/proxyTargetClass " +
  114. "attribute to 'true'", method.getName(),
  115. method.getDeclaringClass().getSimpleName()), ex);
  116. }
  117. }
  118. return method;
  119. }
  120. /**
  121. * 获取类上的 {@link DynamicMethod} 注解
  122. *
  123. * @param clazz 类
  124. * @return {@link DynamicMethod} 注解集合
  125. */
  126. private Collection<DynamicClass> findConsumerClass(Class<?> clazz) {
  127. Set<DynamicClass> consumerMethods = new HashSet<>();
  128. DynamicClass ann = AnnotationUtils.findAnnotation(clazz, DynamicClass.class);
  129. if (ann != null) {
  130. consumerMethods.add(ann);
  131. }
  132. return consumerMethods;
  133. }
  134. /**
  135. * 获取方法上的 {@link DynamicMethod} 注解
  136. *
  137. * @param method 方法
  138. * @return {@link DynamicMethod} 注解集合
  139. */
  140. private Set<DynamicMethod> findConsumerClass(Method method) {
  141. Set<DynamicMethod> dynamicMethods = new HashSet<>();
  142. DynamicMethod ann = AnnotatedElementUtils.findMergedAnnotation(method, DynamicMethod.class);
  143. if (ann != null) {
  144. dynamicMethods.add(ann);
  145. }
  146. return dynamicMethods;
  147. }
  148. @Override
  149. public int getOrder() {
  150. return LOWEST_PRECEDENCE;
  151. }
  152. }