zoukankan      html  css  js  c++  java
  • 模拟Spring自实现监听器

    模拟Spring自实现监听器

    组件:

      事件(Event):即监听什么。如任务即将执行、任务执行完毕

      监听器(Listener):谁来监听,<E extends Event> :E,对什么时间感兴趣(监听特定类型的事件)

      广播器(Multicaster):发布事件、添加/移除监听器

      事件触发机制:事件什么时候发布

    1、事件 抽象类Event,其他要监控的事件继承它

    /**
     * 事件
     *
     * @author yangyongjie
     * @date 2020/9/30
     * @desc
     */
    public abstract class Event<T> {
        /**
         * 事件自身资源,用来发布任务时传递一些参数信息
         */
        protected T source;
        /**
         * 事件发生时间
         */
        private final long timestamp;
    
        public Event(T source) {
            this.source = source;
            this.timestamp = System.currentTimeMillis();
        }
    
        public T getSource() {
            return source;
        }
    
        public void setSource(T source) {
            this.source = source;
        }
    
        public long getTimestamp() {
            return timestamp;
        }
    }

     如流程结束事件:

    /**
     * 审批流程结束事件
     *
     * @author yangyongjie
     * @date 2020/10/15
     * @desc
     */
    public class AuditFlowFinishEvent extends Event<AuditFlow> {
    
        public AuditFlowFinishEvent(AuditFlow auditFlow) {
            super(auditFlow);
        }
    
    }

    2、监听器接口 Listener,自定义监听器实现它;泛型E表示要监听的事件 

    /**
     * 监听器
     *
     * @author yangyongjie
     * @date 2020/9/30
     * @desc
     */
    public interface Listener<E extends Event> {
    
        /**
         * 当事件发生做一些事情
         *
         * @param event
         */
        void onEvent(E event);
    }

     如:审核流程结束监听器

    /**
     * 审核流程结束监听器
     *
     * @author yangyongjie
     * @date 2020/10/15
     * @desc
     */
    @Component
    public class AuditFlowFinishListener implements Listener<AuditFlowFinishEvent> {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(AuditFlowFinishListener.class);
    
        @Override
        public void onEvent(AuditFlowFinishEvent event) {
            AuditFlow auditFlow = event.getSource();
            LOGGER.info("流程结束监听器工作了!");
        }
    }

    3、广播器,管理监听器,发布事件 (需注入到Spring容器中)

     V1.0:

     1)广播器接口:

    /**
     * 事件广播器
     *
     * @author yangyongjie
     * @date 2020/9/30
     * @desc
     */
    public interface EventMulticaster {
    
        /**
         * 添加监听器
         *
         * @param listener
         */
        void addListener(Listener<?> listener);
    
        /**
         * 移除监听器
         *
         * @param listener
         */
        void removeListener(Listener<?> listener);
    
        /**
         * 发布事件
         *
         * @param event
         */
        void multicastEvent(Event event);
    
    }

     2)广播器实现类

    import org.apache.commons.lang.StringUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.LinkedHashSet;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 广播器(事件发布器)
     *
     * @author yangyongjie
     * @date 2020/10/15
     * @desc
     */
    @Component
    public class SimpleEventMulticaster implements EventMulticaster, ApplicationContextAware {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(SimpleEventMulticaster.class);
    
        private final Set<Listener<?>> listeners = new LinkedHashSet<>();
    
        /**
         * 创建一个执行监听器线程池,核心线程数为1,最大线程数为5,线程空闲时间为60s,拒绝策略为打印日志并直接执行被拒绝的任务
         */
        private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(1, 5, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(50), new CustomThreadFactory("simpleEventMulticaster"), (r, executor) -> {
            LOGGER.error("Task:{},rejected from:{}", r.toString(), executor.toString());
            // 直接执行被拒绝的任务,JVM另起线程执行
            r.run();
        });
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            // 获取容器中实现Listener接口的监听器,并添加到listeners缓存中
            Map<String, Listener> listenerMap = applicationContext.getBeansOfType(Listener.class);
            for (Map.Entry<String, Listener> entry : listenerMap.entrySet()) {
                addListener(entry.getValue());
            }
        }
    
        @Override
        public void addListener(Listener<?> listener) {
            this.listeners.add(listener);
        }
    
        @Override
        public void removeListener(Listener<?> listener) {
            this.listeners.remove(listener);
        }
    
        @Override
        public void multicastEvent(final Event event) {
            multicastEvent(event, true);
        }
    
        /**
         * 是否异步,默认true
         *
         * @param event
         * @param async
         */
        public void multicastEvent(final Event event, boolean async) {
            Class eventClass = event.getClass();
            Set<Listener> interestedListeners = getInterestedListeners(eventClass);
            // 事件发生,异步调用监听器的事件方法
            if (async) {
                for (final Listener listener : interestedListeners) {
                    EXECUTOR.execute(() -> listener.onEvent(event));
                }
            } else {
                for (final Listener listener : interestedListeners) {
                    listener.onEvent(event);
                }
            }
    
        }
    
        /**
         * 获取对当前事件感兴趣的监听器
         *
         * @param eventClass
         */
        private Set<Listener> getInterestedListeners(Class eventClass) {
            // 存放监听对发布事件感兴趣的监听器
            Set<Listener> interestedListeners = new LinkedHashSet<>();
            for (Listener listener : listeners) {
                // 获取监听器的泛型类型
                ParameterizedType parameterizedType = (ParameterizedType) listener.getClass().getGenericInterfaces()[0];
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                Listener filterListener = null;
                for (Type actualTypeArgument : actualTypeArguments) {
                    if (StringUtils.equals(eventClass.getName(), actualTypeArgument.getTypeName())) {
                        filterListener = listener;
                    }
                }
                if (filterListener != null) {
                    interestedListeners.add(filterListener);
                }
            }
            return interestedListeners;
        }
    
    }

      注1:1.8之前版本  actualTypeArgument.getTypeName() 替换成  ((Class) actualTypeArgument).getName() ;并替换掉 Lambda表达式

      注2:若在监听器的onEvent方法上加了@Transactional注解,那么获取到的监听器的对象就是代理对象,在获取监听器泛型的时候会有问题,需要拿到被代理的目标类对象,然后再去获取泛型类型:

      修改后的getInterestedListeners()方法的for循环第一行:

      ParameterizedType parameterizedType = (ParameterizedType) AopTargetUtil.getTarget(listener).getClass().getGenericInterfaces()[0];

      V2.0:

      1)广播器接口:

    /**
     * 事件广播器
     *
     * @author yangyongjie
     * @date 2020/9/30
     * @desc
     */
    public interface EventMulticaster {
    
        /**
         * 添加监听器
         *
         * @param listener
         */
        void addListener(Listener<?> listener);
    
        /**
         * 移除监听器
         *
         * @param listener
         */
        void removeListener(Listener<?> listener);
    
        /**
         * 发布事件,默认异步执行监听
         *
         * @param event
         */
        void multicastEvent(Event<?> event);
    
        /**
         * 发布事件,按参数确定异步还是同步执行监听
         *
         * @param event
         * @param async
         */
        void multicastEvent(Event<?> event, boolean async);
    
    }

      2)广播器实现类:

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.aop.support.AopUtils;
    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.core.ResolvableType;
    import org.springframework.stereotype.Component;
    
    import java.util.LinkedHashSet;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.LinkedBlockingQueue;
    import java.util.concurrent.ThreadPoolExecutor;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 广播器(事件发布器)
     *
     * @author yangyongjie
     * @date 2021/1/28
     */
    @Component
    public class SimpleEventMulticaster implements EventMulticaster, ApplicationContextAware {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(SimpleEventMulticaster.class);
    
        /**
         * 所有监听器的集合
         */
        private final Set<Listener<?>> listeners = new LinkedHashSet<>();
    
        /**
         * 创建一个执行监听器线程池,核心线程数为2,最大线程数为5,线程空闲时间为60s,拒绝策略为打印日志并直接执行被拒绝的任务
         * 线程数和队列依具体业务而定
         */
        private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(
                2,
                5,
                60, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(50),
                new CustomThreadFactory("simpleEventMulticaster"),
                (r, executor) -> {
                    LOGGER.error("Task:{},rejected from:{}", r.toString(), executor.toString());
                    // 直接执行被拒绝的任务,JVM另起线程执行
                    r.run();
                });
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            // 获取容器中实现Listener接口的监听器,并添加到listeners缓存中
            Map<String, Listener> listenerMap = applicationContext.getBeansOfType(Listener.class);
            for (Map.Entry<String, Listener> entry : listenerMap.entrySet()) {
                addListener(entry.getValue());
            }
        }
    
        @Override
        public void addListener(Listener<?> listener) {
            this.listeners.add(listener);
        }
    
        @Override
        public void removeListener(Listener<?> listener) {
            this.listeners.remove(listener);
        }
    
        /**
         * 发布事件
         *
         * @param event
         */
        @Override
        public void multicastEvent(Event<?> event) {
            multicastEvent(event, true);
        }
    
        @Override
        public void multicastEvent(Event<?> event, boolean async) {
            Class eventClass = event.getClass();
            Set<Listener<?>> interestedListeners = getInterestedListeners(eventClass);
            // 事件发生,异步调用监听器的事件方法
            for (Listener<?> listener : interestedListeners) {
                if (async) {
                    EXECUTOR.execute(() -> invokeListener(listener, event));
                } else {
                    invokeListener(listener, event);
                }
            }
        }
    
        /**
         * 触发监听器事件处理
         *
         * @param listener
         * @param event
         */
        private void invokeListener(Listener listener, Event event) {
            try {
                listener.onEvent(event);
            } catch (Exception e) {
                LOGGER.error(e.getMessage(), e);
            }
        }
    
        /**
         * 获取对当前事件感兴趣的监听器(监听了当前事件或当前事件的父事件)
         *
         * @param eventClass
         */
        private Set<Listener<?>> getInterestedListeners(Class eventClass) {
            // 存放监听对发布事件感兴趣的监听器
            Set<Listener<?>> interestedListeners = new LinkedHashSet<>();
            for (Listener<?> listener : listeners) {
                // 避免listener被aop代理,因此获取其被代理的listener
                Class<?> targetClass = AopUtils.getTargetClass(listener);
                // 获取监听器的泛型类型(即监听器监听的事件类型)
                ResolvableType genericEventType = ResolvableType.forClass(targetClass).as(Listener.class).getGeneric();
                // 监听器监听的事件类型是否是发布事件类型的父类 或与发布的事件类型相同
                if (genericEventType.isAssignableFrom(eventClass)) {
                    interestedListeners.add(listener);
                }
            }
            return interestedListeners;
        }
    
    }

    4、使用广播器发布事件(在事件源中发布事件)

        @Autowired
        private EventMulticaster eventMulticaster;
    
        // 发布事件
        eventMulticaster.multicastEvent(new AuditFlowFinishEvent(auditFlow));

     附录

     1)AopTargetUtil:

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.aop.framework.AdvisedSupport;
    import org.springframework.aop.framework.AopProxy;
    import org.springframework.aop.support.AopUtils;
    
    import java.lang.reflect.Field;
    
    /**
     * 通过代理对象获取被代理的目标对象
     *
     * @author yangyongjie
     * @date 2020/12/10
     * @desc
     */
    public class AopTargetUtil {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(AopTargetUtil.class);
    
        private AopTargetUtil() {
        }
    
        /**
         * 获取 目标对象
         *
         * @param proxy 代理对象
         * @return
         * @throws Exception
         */
        public static Object getTarget(Object proxy) {
    
            // 不是代理对象,即没有被aop代理,直接返回
            if (!AopUtils.isAopProxy(proxy)) {
                return proxy;
            }
            try {
                // cglibProxy
                if (AopUtils.isCglibProxy(proxy)) {
                    return getCglibProxyTargetObject(proxy);
                    // jdkDynamicProxy
                } else {
                    return getJdkDynamicProxyTargetObject(proxy);
                }
            } catch (Exception e) {
                LOGGER.error("获取被代理类对象异常:" + e.getMessage(), e);
                return proxy;
            }
        }
    
    
        /**
         * CGLIB方式被代理类的获取
         *
         * @param proxy
         * @return
         * @throws Exception
         */
        private static Object getCglibProxyTargetObject(Object proxy) throws Exception {
            Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0");
            h.setAccessible(true);
            Object dynamicAdvisedInterceptor = h.get(proxy);
    
            Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised");
            advised.setAccessible(true);
    
            Object target = ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget();
    
            return target;
        }
    
        /**
         * JDK动态代理方式被代理类的获取
         *
         * @param proxy
         * @return
         * @throws Exception
         */
        private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception {
            Field h = proxy.getClass().getSuperclass().getDeclaredField("h");
            h.setAccessible(true);
            AopProxy aopProxy = (AopProxy) h.get(proxy);
    
            Field advised = aopProxy.getClass().getDeclaredField("advised");
            advised.setAccessible(true);
    
            Object target = ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget();
    
            return target;
        }
    
    }
    View Code

     2)org.springframework.aop.support.AopUtils:

    /*
     * Copyright 2002-2019 the original author or authors.
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     *      https://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package org.springframework.aop.support;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.lang.reflect.Proxy;
    import java.util.ArrayList;
    import java.util.LinkedHashSet;
    import java.util.List;
    import java.util.Set;
    
    import org.springframework.aop.Advisor;
    import org.springframework.aop.AopInvocationException;
    import org.springframework.aop.IntroductionAdvisor;
    import org.springframework.aop.IntroductionAwareMethodMatcher;
    import org.springframework.aop.MethodMatcher;
    import org.springframework.aop.Pointcut;
    import org.springframework.aop.PointcutAdvisor;
    import org.springframework.aop.SpringProxy;
    import org.springframework.aop.TargetClassAware;
    import org.springframework.core.BridgeMethodResolver;
    import org.springframework.core.MethodIntrospector;
    import org.springframework.lang.Nullable;
    import org.springframework.util.Assert;
    import org.springframework.util.ClassUtils;
    import org.springframework.util.ReflectionUtils;
    
    /**
     * Utility methods for AOP support code.
     *
     * <p>Mainly for internal use within Spring's AOP support.
     *
     * <p>See {@link org.springframework.aop.framework.AopProxyUtils} for a
     * collection of framework-specific AOP utility methods which depend
     * on internals of Spring's AOP framework implementation.
     *
     * @author Rod Johnson
     * @author Juergen Hoeller
     * @author Rob Harrop
     * @see org.springframework.aop.framework.AopProxyUtils
     */
    public abstract class AopUtils {
    
        /**
         * Check whether the given object is a JDK dynamic proxy or a CGLIB proxy.
         * <p>This method additionally checks if the given object is an instance
         * of {@link SpringProxy}.
         * @param object the object to check
         * @see #isJdkDynamicProxy
         * @see #isCglibProxy
         */
        public static boolean isAopProxy(@Nullable Object object) {
            return (object instanceof SpringProxy && (Proxy.isProxyClass(object.getClass()) ||
                    object.getClass().getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR)));
        }
    
        /**
         * Check whether the given object is a JDK dynamic proxy.
         * <p>This method goes beyond the implementation of
         * {@link Proxy#isProxyClass(Class)} by additionally checking if the
         * given object is an instance of {@link SpringProxy}.
         * @param object the object to check
         * @see java.lang.reflect.Proxy#isProxyClass
         */
        public static boolean isJdkDynamicProxy(@Nullable Object object) {
            return (object instanceof SpringProxy && Proxy.isProxyClass(object.getClass()));
        }
    
        /**
         * Check whether the given object is a CGLIB proxy.
         * <p>This method goes beyond the implementation of
         * {@link ClassUtils#isCglibProxy(Object)} by additionally checking if
         * the given object is an instance of {@link SpringProxy}.
         * @param object the object to check
         * @see ClassUtils#isCglibProxy(Object)
         */
        public static boolean isCglibProxy(@Nullable Object object) {
            return (object instanceof SpringProxy &&
                    object.getClass().getName().contains(ClassUtils.CGLIB_CLASS_SEPARATOR));
        }
    
        /**
         * Determine the target class of the given bean instance which might be an AOP proxy.
         * <p>Returns the target class for an AOP proxy or the plain class otherwise.
         * @param candidate the instance to check (might be an AOP proxy)
         * @return the target class (or the plain class of the given object as fallback;
         * never {@code null})
         * @see org.springframework.aop.TargetClassAware#getTargetClass()
         * @see org.springframework.aop.framework.AopProxyUtils#ultimateTargetClass(Object)
         */
        public static Class<?> getTargetClass(Object candidate) {
            Assert.notNull(candidate, "Candidate object must not be null");
            Class<?> result = null;
            if (candidate instanceof TargetClassAware) {
                result = ((TargetClassAware) candidate).getTargetClass();
            }
            if (result == null) {
                result = (isCglibProxy(candidate) ? candidate.getClass().getSuperclass() : candidate.getClass());
            }
            return result;
        }
    
        /**
         * Select an invocable method on the target type: either the given method itself
         * if actually exposed on the target type, or otherwise a corresponding method
         * on one of the target type's interfaces or on the target type itself.
         * @param method the method to check
         * @param targetType the target type to search methods on (typically an AOP proxy)
         * @return a corresponding invocable method on the target type
         * @throws IllegalStateException if the given method is not invocable on the given
         * target type (typically due to a proxy mismatch)
         * @since 4.3
         * @see MethodIntrospector#selectInvocableMethod(Method, Class)
         */
        public static Method selectInvocableMethod(Method method, @Nullable Class<?> targetType) {
            if (targetType == null) {
                return method;
            }
            Method methodToUse = MethodIntrospector.selectInvocableMethod(method, targetType);
            if (Modifier.isPrivate(methodToUse.getModifiers()) && !Modifier.isStatic(methodToUse.getModifiers()) &&
                    SpringProxy.class.isAssignableFrom(targetType)) {
                throw new IllegalStateException(String.format(
                        "Need to invoke method '%s' found on proxy for target class '%s' but cannot " +
                        "be delegated to target bean. Switch its visibility to package or protected.",
                        method.getName(), method.getDeclaringClass().getSimpleName()));
            }
            return methodToUse;
        }
    
        /**
         * Determine whether the given method is an "equals" method.
         * @see java.lang.Object#equals
         */
        public static boolean isEqualsMethod(@Nullable Method method) {
            return ReflectionUtils.isEqualsMethod(method);
        }
    
        /**
         * Determine whether the given method is a "hashCode" method.
         * @see java.lang.Object#hashCode
         */
        public static boolean isHashCodeMethod(@Nullable Method method) {
            return ReflectionUtils.isHashCodeMethod(method);
        }
    
        /**
         * Determine whether the given method is a "toString" method.
         * @see java.lang.Object#toString()
         */
        public static boolean isToStringMethod(@Nullable Method method) {
            return ReflectionUtils.isToStringMethod(method);
        }
    
        /**
         * Determine whether the given method is a "finalize" method.
         * @see java.lang.Object#finalize()
         */
        public static boolean isFinalizeMethod(@Nullable Method method) {
            return (method != null && method.getName().equals("finalize") &&
                    method.getParameterCount() == 0);
        }
    
        /**
         * Given a method, which may come from an interface, and a target class used
         * in the current AOP invocation, find the corresponding target method if there
         * is one. E.g. the method may be {@code IFoo.bar()} and the target class
         * may be {@code DefaultFoo}. In this case, the method may be
         * {@code DefaultFoo.bar()}. This enables attributes on that method to be found.
         * <p><b>NOTE:</b> In contrast to {@link org.springframework.util.ClassUtils#getMostSpecificMethod},
         * this method resolves Java 5 bridge methods in order to retrieve attributes
         * from the <i>original</i> method definition.
         * @param method the method to be invoked, which may come from an interface
         * @param targetClass the target class for the current invocation.
         * May be {@code null} or may not even implement the method.
         * @return the specific target method, or the original method if the
         * {@code targetClass} doesn't implement it or is {@code null}
         * @see org.springframework.util.ClassUtils#getMostSpecificMethod
         */
        public static Method getMostSpecificMethod(Method method, @Nullable Class<?> targetClass) {
            Class<?> specificTargetClass = (targetClass != null ? ClassUtils.getUserClass(targetClass) : null);
            Method resolvedMethod = ClassUtils.getMostSpecificMethod(method, specificTargetClass);
            // If we are dealing with method with generic parameters, find the original method.
            return BridgeMethodResolver.findBridgedMethod(resolvedMethod);
        }
    
        /**
         * Can the given pointcut apply at all on the given class?
         * <p>This is an important test as it can be used to optimize
         * out a pointcut for a class.
         * @param pc the static or dynamic pointcut to check
         * @param targetClass the class to test
         * @return whether the pointcut can apply on any method
         */
        public static boolean canApply(Pointcut pc, Class<?> targetClass) {
            return canApply(pc, targetClass, false);
        }
    
        /**
         * Can the given pointcut apply at all on the given class?
         * <p>This is an important test as it can be used to optimize
         * out a pointcut for a class.
         * @param pc the static or dynamic pointcut to check
         * @param targetClass the class to test
         * @param hasIntroductions whether or not the advisor chain
         * for this bean includes any introductions
         * @return whether the pointcut can apply on any method
         */
        public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
            Assert.notNull(pc, "Pointcut must not be null");
            if (!pc.getClassFilter().matches(targetClass)) {
                return false;
            }
    
            MethodMatcher methodMatcher = pc.getMethodMatcher();
            if (methodMatcher == MethodMatcher.TRUE) {
                // No need to iterate the methods if we're matching any method anyway...
                return true;
            }
    
            IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
            if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
                introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
            }
    
            Set<Class<?>> classes = new LinkedHashSet<>();
            if (!Proxy.isProxyClass(targetClass)) {
                classes.add(ClassUtils.getUserClass(targetClass));
            }
            classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
    
            for (Class<?> clazz : classes) {
                Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
                for (Method method : methods) {
                    if (introductionAwareMethodMatcher != null ?
                            introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
                            methodMatcher.matches(method, targetClass)) {
                        return true;
                    }
                }
            }
    
            return false;
        }
    
        /**
         * Can the given advisor apply at all on the given class?
         * This is an important test as it can be used to optimize
         * out a advisor for a class.
         * @param advisor the advisor to check
         * @param targetClass class we're testing
         * @return whether the pointcut can apply on any method
         */
        public static boolean canApply(Advisor advisor, Class<?> targetClass) {
            return canApply(advisor, targetClass, false);
        }
    
        /**
         * Can the given advisor apply at all on the given class?
         * <p>This is an important test as it can be used to optimize out a advisor for a class.
         * This version also takes into account introductions (for IntroductionAwareMethodMatchers).
         * @param advisor the advisor to check
         * @param targetClass class we're testing
         * @param hasIntroductions whether or not the advisor chain for this bean includes
         * any introductions
         * @return whether the pointcut can apply on any method
         */
        public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
            if (advisor instanceof IntroductionAdvisor) {
                return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
            }
            else if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pca = (PointcutAdvisor) advisor;
                return canApply(pca.getPointcut(), targetClass, hasIntroductions);
            }
            else {
                // It doesn't have a pointcut so we assume it applies.
                return true;
            }
        }
    
        /**
         * Determine the sublist of the {@code candidateAdvisors} list
         * that is applicable to the given class.
         * @param candidateAdvisors the Advisors to evaluate
         * @param clazz the target class
         * @return sublist of Advisors that can apply to an object of the given class
         * (may be the incoming List as-is)
         */
        public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
            if (candidateAdvisors.isEmpty()) {
                return candidateAdvisors;
            }
            List<Advisor> eligibleAdvisors = new ArrayList<>();
            for (Advisor candidate : candidateAdvisors) {
                if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
                    eligibleAdvisors.add(candidate);
                }
            }
            boolean hasIntroductions = !eligibleAdvisors.isEmpty();
            for (Advisor candidate : candidateAdvisors) {
                if (candidate instanceof IntroductionAdvisor) {
                    // already processed
                    continue;
                }
                if (canApply(candidate, clazz, hasIntroductions)) {
                    eligibleAdvisors.add(candidate);
                }
            }
            return eligibleAdvisors;
        }
    
        /**
         * Invoke the given target via reflection, as part of an AOP method invocation.
         * @param target the target object
         * @param method the method to invoke
         * @param args the arguments for the method
         * @return the invocation result, if any
         * @throws Throwable if thrown by the target method
         * @throws org.springframework.aop.AopInvocationException in case of a reflection error
         */
        @Nullable
        public static Object invokeJoinpointUsingReflection(@Nullable Object target, Method method, Object[] args)
                throws Throwable {
    
            // Use reflection to invoke the method.
            try {
                ReflectionUtils.makeAccessible(method);
                return method.invoke(target, args);
            }
            catch (InvocationTargetException ex) {
                // Invoked method threw a checked exception.
                // We must rethrow it. The client won't see the interceptor.
                throw ex.getTargetException();
            }
            catch (IllegalArgumentException ex) {
                throw new AopInvocationException("AOP configuration seems to be invalid: tried calling method [" +
                        method + "] on target [" + target + "]", ex);
            }
            catch (IllegalAccessException ex) {
                throw new AopInvocationException("Could not access method [" + method + "]", ex);
            }
        }
    
    }
    View Code

    END.

  • 相关阅读:
    VisualVM 分析full GC问题记录
    HTTPS协议、TLS协议、证书认证过程解析
    java.lang基础数据类型boolean、char、byte、short、int、long、float、double (JDK1.8)
    java.lang.StringBuilder和java.lang.StringBuffer (JDK1.8)
    MVC中自带的异步((Ajax.BeginForm)无效
    百度富文本编辑器UEDITOR
    只有在配置文件或 Page 指令中将 enableSessionState 设置为 true 时,才能使用会话状态。还请确保在应用程序配置的 // 节中包括 System.Web.SessionSta
    【知识碎片】CSS 篇
    js 将json字符串转换为json对象的方法解析
    【知识碎片】Asp.Net 篇
  • 原文地址:https://www.cnblogs.com/yangyongjie/p/14337665.html
Copyright © 2011-2022 走看看