一、@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);
}
}
}