spring @order控制对象的顺序

一、@order控制 @component,@configutation内的@BEAN的加载和实例化顺序。主要是在

ConfigurationClassPostProcessor.processConfigBeanDefinitions中加载调整顺序,

		// Return immediately if no @Configuration classes were found
		if (configCandidates.isEmpty()) {
			return;
		}

		// Sort by previously determined @Order value, if applicable
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		// Detect any custom bean name generation strategy supplied through the enclosing application context
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry) {
			sbr = (SingletonBeanRegistry) registry;
			if (!this.localBeanNameGeneratorSet) {
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}

二、@order控制 @aspect的切面执行顺序,数值越小优先级越高。

spring aop就是一个同心圆,要执行的方法为圆心,最外层的order最小。从最外层按照AOP1、AOP2的顺序依次执行doAround方法,doBefore方法。然后执行method方法,最后按照AOP2、AOP1的顺序依次执行doAfter、doAfterReturn方法。也就是说对多个AOP来说,先before的,一定后after。

如果我们要在同一个方法事务提交后执行自己的AOP,那么把事务的AOP order设置为2,自己的AOP order设置为1,然后在doAfterReturn里边处理自己的业务逻辑。

示例代码:

package com.tpw.newday.aspect;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.tpw.newday.annation.CacheProcesser;
import com.tpw.newday.common.MyConstants;
import com.tpw.newday.redis.RedisParam;
import com.tpw.newday.redis.RedisService;
import com.tpw.newday.utils.RedisUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.validation.constraints.Null;
import java.lang.reflect.Method;

/**
 * <h3>newday</h3>
 * <p>xx</p>
 *
 * @author : lipengyao
 * @date : 2021-04-30 15:56:19
 **/
@Aspect
@Component
@Order(2)
public class CacheAspect {

    private static final Log logger = LogFactory.getLog(CacheAspect.class);

    private RedisUtil redisUtil = new RedisUtil(MyConstants.redis_host_ip,MyConstants.redis_port,MyConstants.redis_password);

    @Autowired
    private RedisService redisService;

    @Pointcut("execution(* com.tpw.newday.service..*.*(..)))")
    private void cacheMethod() {

    }

    /**
     * 前置通知:在目标方法执行前调用
     */
    @Before("cacheMethod()")
    public void begin() {
        logger.info("==@Before== lipy cache method : begin");
    }

    /**
     * 后置通知:在目标方法执行后调用,若目标方法出现异常,则不执行
     */
    @AfterReturning(value = "cacheMethod()",returning = "ret")
    public void afterReturning(JoinPoint jp,Object ret) {
        Object[] args = jp.getArgs();
        logger.info("==@AfterReturning== lipy cache method : after returning ret:" + JSONUtil.toJsonStr(ret)
        +" args:" + JSONUtil.toJsonStr(args));
    }

    /**
     * 后置/最终通知:无论目标方法在执行过程中出现一场都会在它之后调用
     */
    @After("cacheMethod()")
    public void after() {
        logger.info("==@After== lipy cache method : finally returning");
    }

    /**
     * 异常通知:目标方法抛出异常时执行
     */
    @AfterThrowing(value = "cacheMethod()",throwing = "ex")
    public void afterThrowing(Throwable ex) {
        logger.info("==@AfterThrowing==  lipy cache method : after throwing ex:" + ex.getMessage());
    }

    /**
     * 环绕通知:灵活自由的在目标方法中切入代码
     */
    @Around("cacheMethod()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取目标方法的名称
        String methodName = joinPoint.getSignature().getName();
        // 获取方法传入参数
        Object[] params = joinPoint.getArgs();
        logger.info("==@Around== lipy cache method --》begin method name " + methodName + " args " + (params.length > 0 ? params[0] :
        null));
        Object result  =  handleMethod(joinPoint);
        logger.info("==@Around== lipy cache method --》end method name " + methodName + " result " + JSONUtil.toJsonStr(result));
        return  result;
    }
}

切面2:

package com.tpw.newday.aspect;

import cn.hutool.json.JSONUtil;
import com.tpw.newday.common.MyConstants;
import com.tpw.newday.redis.RedisService;
import com.tpw.newday.utils.RedisUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * <h3>newday</h3>
 * <p></p>
 *
 * @author : lipengyao
 * @date : 2021-07-06 14:24:37
 **/
@Component
@Aspect
@Order(1)
public class MqAopAspect  {
    private static final Log logger = LogFactory.getLog(MqAopAspect.class);


    @Pointcut("@annotation(com.tpw.newday.annation.MqAop)")
    private void mqMethod() {

    }

    /**
     * 前置通知:在目标方法执行前调用
     */
    @Before("mqMethod()")
    public void begin() {
        logger.info("==@Before== lipy mq method : begin");
    }

    /**
     * 后置通知:在目标方法执行后调用,若目标方法出现异常,则不执行
     */
    @AfterReturning("mqMethod()")
    public void afterReturning() {
        logger.info("==@AfterReturning== mq  method : after returning");
    }

    /**
     * 后置/最终通知:无论目标方法在执行过程中出现一场都会在它之后调用
     */
    @After("mqMethod()")
    public void after() {
        logger.info("==@After== lipy mq method : finally returning");
    }

    /**
     * 异常通知:目标方法抛出异常时执行
     */
    @AfterThrowing("mqMethod()")
    public void afterThrowing() {
        logger.info("==@AfterThrowing==  lipy mq method : after throwing");
    }

    /**
     * 环绕通知:灵活自由的在目标方法中切入代码
     */
    @Around("mqMethod()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取目标方法的名称
        String methodName = joinPoint.getSignature().getName();
        // 获取方法传入参数
        Object[] params = joinPoint.getArgs();
        logger.info("==@Around== lipy mq method --》begin method name " + methodName + " args " + (params.length > 0 ? params[0] :
                null));
        Object result =  joinPoint.proceed();
        logger.info("==@Around== lipy mq method --》end method name " + methodName + " result:" + JSONUtil.toJsonStr(result));
        return  result;
    }

}

查看执行结果

2021-07-06 15:07:35.101  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.aspect.MqAopAspect        : ==@Around== lipy mq method --》begin method name getUserById args 1709121331320000
2021-07-06 15:07:35.101  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.aspect.MqAopAspect        : ==@Before== lipy mq method : begin
2021-07-06 15:07:35.101  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.aspect.CacheAspect        : ==@Around== lipy cache method --》begin method name getUserById args 1709121331320000
2021-07-06 15:07:35.123  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.aspect.CacheAspect        : ==@Before== lipy cache method : begin
2021-07-06 15:07:35.125 DEBUG 28644 --- [nio-8080-exec-1] com.tpw.newday.service.UserServiceImpl   :  get begin userid:1709121331320000
2021-07-06 15:07:35.202 DEBUG 28644 --- [nio-8080-exec-1] org.hibernate.SQL                        : 
    select
        a.* 
    from
        sys_user a 
    where
        a.user_id=? 
Hibernate: 
    select
        a.* 
    from
        sys_user a 
    where
        a.user_id=? 
2021-07-06 15:07:35.230 TRACE 28644 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [VARCHAR] - [1709121331320000]
2021-07-06 15:07:35.259 DEBUG 28644 --- [nio-8080-exec-1] com.tpw.newday.service.UserServiceImpl   : u1:com.tpw.newday.local_bean.JpaUser@79a58149
2021-07-06 15:07:35.285  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.service.UserServiceImpl   :  get end userid:1709121331320000
2021-07-06 15:07:35.285 DEBUG 28644 --- [nio-8080-exec-1] com.tpw.newday.service.UserServiceImpl   :  debug test common loging userid:1709121331320000
2021-07-06 15:07:35.285  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.service.UserServiceImpl   :  info test common loging userid:1709121331320000
2021-07-06 15:07:35.285  WARN 28644 --- [nio-8080-exec-1] com.tpw.newday.service.UserServiceImpl   :  warn test common loging userid:1709121331320000
2021-07-06 15:07:35.285  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.aspect.CacheAspect        : ==@AfterReturning== lipy cache method : after returning ret:{"userCreateTime":1512653581000,"userPassword":"root123456","userStatus":"1","userName":"超级管理员","userId":"1709121331320000","roleName":"adminRole","userLoginName":"root"} args:["1709121331320000"]
2021-07-06 15:07:35.285  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.aspect.CacheAspect        : ==@After== lipy cache method : finally returning
2021-07-06 15:07:35.306  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.aspect.CacheAspect        :  call method,set to  cache key:getUserById:1709121331320000
2021-07-06 15:07:35.307  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.aspect.CacheAspect        : ==@Around== lipy cache method --》end method name getUserById result {"userCreateTime":1512653581000,"userPassword":"root123456","userStatus":"1","userName":"超级管理员","userId":"1709121331320000","roleName":"adminRole","userLoginName":"root"}
2021-07-06 15:07:35.307  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.aspect.MqAopAspect        : ==@AfterReturning== mq  method : after returning
2021-07-06 15:07:35.307  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.aspect.MqAopAspect        : ==@After== lipy mq method : finally returning
2021-07-06 15:07:35.307  INFO 28644 --- [nio-8080-exec-1] com.tpw.newday.aspect.MqAopAspect        : ==@Around== lipy mq method --》end method name getUserById result:{"userCreateTime":1512653581000,"userPassword":"root123456","userStatus":"1","userName":"超级管理员","userId":"1709121331320000","roleName":"adminRole","userLoginName":"root"}

三、@order控制同一个接口的多实现版本对象通过构造函数注入的列表对象顺序。是在创建实例对象时,调用自动注入参数的构造函数,会从容器工厂registry中获取依赖的实现此接口参数的所有对象,然后再对参数列表对象进行ORDER排序,最后调用带参数构造函数创建对象。最终实现在DefaultListableBeanFactory.resolveMultipleBeans

@Nullable
	private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {

		Class<?> type = descriptor.getDependencyType();
		 if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
			Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
			if (elementType == null) {
				return null;
			}
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
					new MultiElementDescriptor(descriptor));
			if (matchingBeans.isEmpty()) {
				return null;
			}
			if (autowiredBeanNames != null) {
				autowiredBeanNames.addAll(matchingBeans.keySet());
			}
			TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
			Object result = converter.convertIfNecessary(matchingBeans.values(), type);
			if (result instanceof List) {
				if (((List<?>) result).size() > 1) {
					Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
					if (comparator != null) {
						((List<?>) result).sort(comparator);
					}
				}
			}
			return result;
		}
		
	}

 测试代码:

@Service
public class RunServiceImpl {

    public static interface DemoService{
        void say();
    }

    @Service
    @Order(-2)
    public static  class DemoServiceImpl01 implements DemoService {

        public DemoServiceImpl01() {
            System.out.println("DemoServiceImpl01被实例化了");
        }

        @Override
        public void say() {
            System.out.println("DemoServiceImpl01被执行了");
        }
    }

    @Service
    @Order(0)
    public static class DemoServiceImpl02 implements DemoService {

        public DemoServiceImpl02() {
            System.out.println("DemoServiceImpl02被实例化了");
        }

        @Override
        public void say() {
            System.out.println("DemoServiceImpl02被执行了");
        }
    }

    @Service
    @Order(-1)
    public static class DemoServiceImpl03 implements DemoService {

        public DemoServiceImpl03() {
            System.out.println("DemoServiceImpl03被实例化了");
        }

        @Override
        public void say() {
            System.out.println("DemoServiceImpl03被执行了");
        }
    }


    public RunServiceImpl(List<DemoService> demoServices) {
//        AnnotationAwareOrderComparator
        demoServices.forEach(t->t.say());
    }
}

四、@order控制同一个对象上的多个condition条件的判断顺序。

ConditionEvaluator.shouldSkip 方法中。
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
		if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
			return false;
		}

		if (phase == null) {
			if (metadata instanceof AnnotationMetadata &&
					ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
				return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
			}
			return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
		}

		List<Condition> conditions = new ArrayList<>();
		for (String[] conditionClasses : getConditionClasses(metadata)) {
			for (String conditionClass : conditionClasses) {
				Condition condition = getCondition(conditionClass, this.context.getClassLoader());
				conditions.add(condition);
			}
		}

		AnnotationAwareOrderComparator.sort(conditions);

		for (Condition condition : conditions) {
			ConfigurationPhase requiredPhase = null;
			if (condition instanceof ConfigurationCondition) {
				requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
			}
			if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
				return true;
			}
		}

		return false;
	}

五、EventListenerFactory进行排序。在EventListenerMethodProcessor.postProcessBeanFactory中进行排序处理。

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		this.beanFactory = beanFactory;

		Map<String, EventListenerFactory> beans = beanFactory.getBeansOfType(EventListenerFactory.class, false, false);
		List<EventListenerFactory> factories = new ArrayList<>(beans.values());
		AnnotationAwareOrderComparator.sort(factories);
		this.eventListenerFactories = factories;
	}

六、ApplicationListener的通知顺序,根据ORDER进行控制。

SimpleApplicationEventMulticaster.multicastEvent
@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值