spring @order控制对象的顺序
一、@order控制 @component,@configutation內的@BEAN的加載和實例化順序。主要是在
ConfigurationClassPostProcessor.processConfigBeanDefinitions中加載調整順序, // Return immediately if no @Configuration classes were foundif (configCandidates.isEmpty()) {return;}// Sort by previously determined @Order value, if applicableconfigCandidates.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 contextSingletonBeanRegistry 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);@Autowiredprivate 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 : selecta.* fromsys_user a wherea.user_id=? Hibernate: selecta.* fromsys_user a wherea.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
@Nullableprivate 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被實例化了");}@Overridepublic void say() {System.out.println("DemoServiceImpl01被執行了");}}@Service@Order(0)public static class DemoServiceImpl02 implements DemoService {public DemoServiceImpl02() {System.out.println("DemoServiceImpl02被實例化了");}@Overridepublic void say() {System.out.println("DemoServiceImpl02被執行了");}}@Service@Order(-1)public static class DemoServiceImpl03 implements DemoService {public DemoServiceImpl03() {System.out.println("DemoServiceImpl03被實例化了");}@Overridepublic void say() {System.out.println("DemoServiceImpl03被執行了");}}public RunServiceImpl(List<DemoService> demoServices) { // AnnotationAwareOrderComparatordemoServices.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中進行排序處理。
@Overridepublic 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 @Overridepublic 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);}}}總結
以上是生活随笔為你收集整理的spring @order控制对象的顺序的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: spring @bean 自动创建容器对
- 下一篇: springboot 的启动流程
