123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- package cn.nosum.support.processor;
- import cn.nosum.support.annotation.DynamicClass;
- import cn.nosum.support.annotation.DynamicMethod;
- import cn.nosum.support.config.DynamicMethodsEndpointRegistrar;
- import cn.nosum.support.endpoint.DynamicMethodWrapper;
- import cn.nosum.support.endpoint.MethodEndpoint;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.aop.framework.Advised;
- import org.springframework.aop.support.AopUtils;
- import org.springframework.beans.BeansException;
- import org.springframework.beans.factory.config.BeanPostProcessor;
- import org.springframework.core.MethodIntrospector;
- import org.springframework.core.Ordered;
- import org.springframework.core.annotation.AnnotatedElementUtils;
- import org.springframework.core.annotation.AnnotationUtils;
- import org.springframework.util.ReflectionUtils;
- import java.lang.reflect.Method;
- import java.util.*;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.stream.Collectors;
- /**
- * Bean post-processor that registers methods annotated with {@link DynamicMethod}.
- *
- * @author Young
- */
- public class DynamicMethodAnnotationBeanPostProcessor implements BeanPostProcessor, Ordered {
- private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
- private final Log logger = LogFactory.getLog(getClass());
- @Override
- public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
- return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
- }
- @Override
- public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- if (this.nonAnnotatedClasses.contains(bean.getClass())) {
- return bean;
- }
- Class<?> targetClass = AopUtils.getTargetClass(bean);
- Collection<DynamicClass> classLevelDynamicMethods = findConsumerClass(targetClass);
- if (classLevelDynamicMethods.isEmpty()){
- return bean;
- }
- Map<Method, Set<DynamicMethod>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
- (MethodIntrospector.MetadataLookup<Set<DynamicMethod>>) method -> {
- Set<DynamicMethod> listenerMethods = findConsumerClass(method);
- return (!listenerMethods.isEmpty() ? listenerMethods : null);
- });
- Set<Method> allMethods = Arrays.stream(bean.getClass().getDeclaredMethods()).filter(method-> !annotatedMethods.containsKey(method)).collect(Collectors.toSet());
- if (allMethods.isEmpty() && annotatedMethods.isEmpty()) {
- this.nonAnnotatedClasses.add(bean.getClass());
- if (this.logger.isTraceEnabled()) {
- this.logger.trace("No @DynamicMethod annotations found on bean type: " + bean.getClass());
- }
- } else {
- // Non-empty set of methods
- for (Map.Entry<Method, Set<DynamicMethod>> entry : annotatedMethods.entrySet()) {
- Method method = entry.getKey();
- for (DynamicMethod dynamicMethod : entry.getValue()) {
- processDynamicMethod(DynamicMethodWrapper.builder().name(dynamicMethod.name()).build(), method, bean, beanName);
- }
- }
- // empty set of methods
- for (Method method : allMethods) {
- processDynamicMethod(DynamicMethodWrapper.builder().name(method.getName()).build(), method, bean, beanName);
- }
- if (this.logger.isDebugEnabled()) {
- this.logger.debug(annotatedMethods.size() + " @DynamicMethod methods processed on bean '"
- + beanName + "': " + annotatedMethods);
- }
- }
- return bean;
- }
- protected void processDynamicMethod(DynamicMethodWrapper dynamicMethod, Method method, Object bean, String beanName) {
- Method methodToUse = checkProxy(method, bean);
- MethodEndpoint endpoint = new MethodEndpoint();
- endpoint.setBean(bean);
- endpoint.setMethod(method);
- processMethod(endpoint, dynamicMethod, bean, methodToUse, beanName);
- }
- protected void processMethod(MethodEndpoint endpoint,
- DynamicMethodWrapper dynamicMethod, Object bean, Object adminTarget, String beanName) {
- endpoint.setBeanName(beanName);
- DynamicMethodsEndpointRegistrar.registerEndpoint(endpoint,dynamicMethod);
- }
- /**
- * 检查代理对象
- *
- * @param methodArg 方法
- * @param bean Bean 实例
- * @return 如果目标类已经被代理,则检查注解是否存在于类本身
- */
- private Method checkProxy(Method methodArg, Object bean) {
- Method method = methodArg;
- if (AopUtils.isJdkDynamicProxy(bean)) {
- try {
- method = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
- Class<?>[] proxiedInterfaces = ((Advised) bean).getProxiedInterfaces();
- for (Class<?> iface : proxiedInterfaces) {
- try {
- method = iface.getMethod(method.getName(), method.getParameterTypes());
- break;
- } catch (NoSuchMethodException ignored) {
- }
- }
- } catch (SecurityException ex) {
- ReflectionUtils.handleReflectionException(ex);
- } catch (NoSuchMethodException ex) {
- throw new IllegalStateException(String.format(
- "@DynamicMethod method '%s' found on bean target class '%s', " +
- "but not found in any interface(s) for bean JDK proxy. Either " +
- "pull the method up to an interface or switch to subclass (CGLIB) " +
- "proxies by setting proxy-target-class/proxyTargetClass " +
- "attribute to 'true'", method.getName(),
- method.getDeclaringClass().getSimpleName()), ex);
- }
- }
- return method;
- }
- /**
- * 获取类上的 {@link DynamicMethod} 注解
- *
- * @param clazz 类
- * @return {@link DynamicMethod} 注解集合
- */
- private Collection<DynamicClass> findConsumerClass(Class<?> clazz) {
- Set<DynamicClass> consumerMethods = new HashSet<>();
- DynamicClass ann = AnnotationUtils.findAnnotation(clazz, DynamicClass.class);
- if (ann != null) {
- consumerMethods.add(ann);
- }
- return consumerMethods;
- }
- /**
- * 获取方法上的 {@link DynamicMethod} 注解
- *
- * @param method 方法
- * @return {@link DynamicMethod} 注解集合
- */
- private Set<DynamicMethod> findConsumerClass(Method method) {
- Set<DynamicMethod> dynamicMethods = new HashSet<>();
- DynamicMethod ann = AnnotatedElementUtils.findMergedAnnotation(method, DynamicMethod.class);
- if (ann != null) {
- dynamicMethods.add(ann);
- }
- return dynamicMethods;
- }
- @Override
- public int getOrder() {
- return LOWEST_PRECEDENCE;
- }
- }
|