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控制对象的顺序相关推荐
- SpringBoot控制配置类加载顺序
1.@Configuration配置被加载进容器的方式大体上可分为3种 手动:构建ApplicationContext时由构建者手动传入,可手动控制顺序. 自动1:被@ComponentScan自动扫 ...
- 使用@Order调整配置类加载顺序
4.1 @Order Spring 4.2 利用@Order控制配置类的加载顺序 4.2 演示 两个演示bean package com.wisely.spring4_2.order;public c ...
- 【转】【iOS知识学习】_视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear等的区别及用途...
原文网址:http://blog.csdn.net/weasleyqi/article/details/8090373 iOS视图控制对象生命周期-init.viewDidLoad.viewWillA ...
- iOS视图控制对象生命周期-init、viewDidLoad、viewWillAppear、v...
2019独角兽企业重金招聘Python工程师标准>>> iOS视图控制对象生命周期-init.viewDidLoad.viewWillAppear.viewDidAppear.vie ...
- iOS视图控制对象生命周期-init、viewDidLoad、viewWillAppear、viewDidAppear、viewWillDisappear、view...
iOS视图控制对象生命周期: init.viewDidLoad.viewWillAppear.viewDidAppear.viewWillDisappear.viewDidDisappear的区别及用 ...
- Spring的控制反转(IOC)和依赖注入(DI)具体解释
Spring的控制反转(IOC)和依赖注入(DI)具体解释 首先介绍下(IOC)控制反转: 所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的.这样控制器就有应 ...
- Spring的控制反转以及依赖注入,控制反转使程序具有高拓展性。
1. 控制反转(Inversion of Control, IOC) 将对象的创建.赋值.管理交给容器(Spring),通过xml文件即可修改对象的属性,不必修改源代码,具有高拓展性.各个模块间的对象 ...
- Spring-学习笔记10【Spring事务控制】
Java后端 学习路线 笔记汇总表[黑马程序员] Spring-学习笔记01[Spring框架简介][day01] Spring-学习笔记02[程序间耦合] Spring-学习笔记03[Spring的 ...
- 查询语句中select from where group by having order by的执行顺序
查询语句中select from where group by having order by的执行顺序 1.查询中用到的关键词主要包含六个,并且他们的顺序依次为 select--from--whe ...
最新文章
- Redis运行流程源码解析--转载
- 【数据结构】集合及运算
- 浅谈 FTP、FTPS 与 SFTP
- Eclipse上Maven环境配置使用
- [Xilinx]Xilinx ISE14.2中调用文本编辑器NotePad++设置方法
- 大众正式发布ID. Buzz 造型致敬经典
- 覆盖17类面试题小结
- Redis(三)源source编译
- Oracle 11g RAC 修改IP
- linux 驱动学习
- Linux中用两个网卡同时上内外网
- 什么是spurious wakeups(虚假唤醒)
- ucla计算机科学博士排名,加州大学洛杉矶分校专业排名一览及最强专业推荐(QS世界大学排名)...
- Python基础综合
- 服务器内网可以打开外网打不开怎么办?网站搭建后打不开怎么办?
- HTML5七夕情人节表白网页(流星动画3D相册) HTML+CSS+JS 求婚 html生日快乐祝福代码网页 520情人节告白代码 程序员表白源码 3D旋转相册 js烟花代码 css爱心表白
- 2020计算机专业保研夏令营面经:北航计算机
- Pwn2Own 2022 温哥华大赛Master of Pwn 诞生
- “工时通”助力新工作方式
- 2021中国各省区块链政策竞争力指数TOP10(3月)|链塔月榜
热门文章
- Oracle--序列和触发器的使用
- ABAP 直接上传图片的函数
- 小朋友嘴里的“金钥匙”,良品小食仙、小鹿蓝蓝们要如何拿到?
- linux控制台单人五子棋简书,Java控制台版五子棋的简单实现方法
- ssh 连接服务器_使用 SSH Key 访问服务器
- 未來用工新趨勢_数字化商业浪潮来袭 未来用工新趋势成焦点
- js富文本编辑器_自制富文本编辑器
- error: a label can only be part of a statement and a declaration is not a statement
- python新手遇到的5大坑
- python中hasattr()、getattr()、setattr()函数的使用