preface
Recently, when looking at the framework, I found this interface. I hope I can give you help and improve myself.
This section describes the ORDER interface
The Spring framework has an interface called Ordered, referring to what we Ordered in the database. It’s easy to think of what it means to order. The question is why Spring defines such a sorting interface. We know that the Spring framework uses a number of policy design patterns. The policy design pattern means that we can have a large number of different implementations of the same interface. So out of all these implementations, which one to execute first and which one to execute next. This creates a ordering and priority problem, and the Ordered interface comes into play to solve this problem.
Official introduction to the Ordered interface
First, let’s take a look at the Spring interface through the source code, which is as follows:
public interface Ordered {
int HIGHEST_PRECEDENCE = -2147483648;
int LOWEST_PRECEDENCE = 2147483647;
int getOrder();
}
Copy the code
From the above code, we can see that the implementation of the Ordered interface is very simple. Has one highest priority and one lowest priority, and also provides a method to get the order value of the current implementation class. Spring order. The smaller the value, the higher the priority, and the larger the value, the lower the priority.
Ordered the application of the interface
After introducing the Ordered interface, let’s look at a real-world application scenario. As a typical scenario, we know that Spring’s transaction management is implemented through an AOP aspect. When we write our own AOP implementation, we cut into a piece of code at the same time as the transaction aspect. So who should Spring execute first? To take a concrete example, we wrote an aspect aspect that switches data sources. If the transaction executes before the data source switch, then the data source switch fails. We definitely want to switch data sources first and then execute the transaction. Here comes ordered’s application scenarios. So let’s say we write the following section.
@Component @aspect public class ChangeDataBase implements Ordered {// Implements service operation @pointcut ()"execution( * com.color.*.service.*.*(..) )")
public void point() {
}
@Before("point()")
public void onlyReadPre() {
DataSourceContextHolder.setDataSourceType(DataSourceType.MYSQL);
System.out.println(MYSQL > Switch to MYSQL > MYSQL);
}
@After("point()")
public void onlyReadPast() {
DataSourceContextHolder.setDataSourceType(DataSourceType.ORACLE);
System.out.println("Switch database back to ORACLE");
}
@Override
public int getOrder() {
return1; }}Copy the code
In the code above, we define a pointcut that intercepts all of the service’s methods. Then before the method executes, we switch the database to mysql and after the method executes, we switch the database to Oracle. Finally, the getOrder method of the ordered interface is overridden. Here we set the level of order to 1. At this point, we are configuring the transaction aspect. Configure order in the XML.
<tx:annotation-driven transaction-manager="transactionManager" order="2"/>
Copy the code
If you are using an injection bean, you can simply implement the interface as above. And that’s when we find out. The method of switching data sources is always executed before the transaction, which serves our purpose.
The use of the ORDER annotation
Now readers are wondering if there is a more convenient way to implement the interface. Sure, let’s introduce the @order annotation. Once again, look at the source code for the Order annotation.
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Documented
public @interface Order {
int value() default 2147483647;
}
Copy the code
The default priority is minimal. We can use the order annotation on the class. We simulate two classes, print the order annotation, and then load the null constructor when the Spring container starts. By printing the null constructor, we can see the order in which the class is initialized and executed. Create our first order class.
@component (1) Public class Order1 {private final int ORDERED = 1; publicOrder1(){
System.out.println(this);
}
@Override
public String toString() {
return "Order1 is loaded @ORDERED=" + ORDERED + "]"; }}Copy the code
Create our second Order class.
@component (2) Public class Order2 {private final int ORDERED = 2; // Order(2) public class Order2 {private final int ORDERED = 2; publicOrder2(){
System.out.println(this);
}
@Override
public String toString() {
return "Order2 is loaded @ORDERED=" + ORDERED + "]"; }}Copy the code
After starting the Spring container, we see the console execute the following result.
Order1 is loaded @ORDERED=1]
Order2 is loaded @ORDERED=2]
Copy the code
The introduction of orderComparator
If you want to know the order value of a class, or if you want to compare the order value of two classes, Spring provides a class for you to do this. OrderComparator, with which we obtain the instance and use the getOrder or compare methods provided by the class. As usual, let’s look at the source first.
public class OrderComparator implements Comparator<Object> {
public static final OrderComparator INSTANCE = new OrderComparator();
public OrderComparator() {
}
public Comparator<Object> withSourceProvider(OrderComparator.OrderSourceProvider sourceProvider) {
return (o1, o2) -> {
return this.doCompare(o1, o2, sourceProvider);
};
}
public int compare(@Nullable Object o1, @Nullable Object o2) {
return this.doCompare(o1, o2, (OrderComparator.OrderSourceProvider)null);
}
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderComparator.OrderSourceProvider sourceProvider) {
boolean p1 = o1 instanceof PriorityOrdered;
boolean p2 = o2 instanceof PriorityOrdered;
if(p1 && ! p2) {return- 1; }else if(p2 && ! p1) {return 1;
} else {
int i1 = this.getOrder(o1, sourceProvider);
int i2 = this.getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
}
}
private int getOrder(@Nullable Object obj, @Nullable OrderComparator.OrderSourceProvider sourceProvider) {
Integer order = null;
if(obj ! = null &&sourceProvider ! = null) { Object orderSource =sourceProvider.getOrderSource(obj);
if(orderSource ! = null) {if (orderSource.getClass().isArray()) {
Object[] sources = ObjectUtils.toObjectArray(orderSource);
Object[] var6 = sources;
int var7 = sources.length;
for(int var8 = 0; var8 < var7; ++var8) {
Object source = var6[var8];
order = this.findOrder(source);
if(order ! = null) {break; }}}else{ order = this.findOrder(orderSource); }}}returnorder ! = null ? order.intValue() : this.getOrder(obj); } protected int getOrder(@Nullable Object obj) {if(obj ! = null) { Integer order = this.findOrder(obj);if(order ! = null) {returnorder.intValue(); }}return 2147483647;
}
@Nullable
protected Integer findOrder(Object obj) {
return obj instanceof Ordered ? ((Ordered)obj).getOrder() : null;
}
@Nullable
public Integer getPriority(Object obj) {
returnnull; } public static void sort(List<? > list) {if (list.size() > 1) {
list.sort(INSTANCE);
}
}
public static void sort(Object[] array) {
if (array.length > 1) {
Arrays.sort(array, INSTANCE);
}
}
public static void sortIfNecessary(Object value) {
if (value instanceof Object[]) {
sort((Object[])((Object[])value));
} else if(value instanceof List) { sort((List)value); } } @FunctionalInterface public interface OrderSourceProvider { @Nullable Object getOrderSource(Object var1); }}Copy the code
Let’s focus first on the doCompare method. The judgment logic is as follows: If o1 is PriorityOrdered, o2 is PriorityOrdered, then o1 has a higher priority than o1. If o1 is PriorityOrdered, O2 is Ordered, then o1 has a higher priority than o2. If both are of the Ordered interface type or PriorityOrdered interface type, call the getOrder method on the Ordered interface to get the order value. The larger the order value, the smaller the priority. If one of the two objects implements the PriorityOrdered interface when the OrderComparator sorts, then that object has a higher priority. If both objects are PriorityOrdered or the implementation class of the Ordered interface, then compare the getOrder method of the Ordered interface to get the order value. The lower the value, the higher the priority.
Look again at the getOrder method. After passing in an object, the provider retrieves the original object. If it is not null, proceed with the judgment. If it’s an array object, you walk through it, you get order, you jump out. Get the order of the object directly if it is not an array. Finally, if the order is not empty, the int value of order is returned. If the order is empty, findOrder returns the maximum value of the order, which is the lowest priority.
protected int getOrder(@Nullable Object obj) {
if(obj ! = null) { Integer order = this.findOrder(obj);if(order ! = null) {returnorder.intValue(); }}return 2147483647;
}
Copy the code
conclusion
At this point, the relevant things of the ordered will be introduced so far. It is inevitable that there are shortcomings in the article. I hope you can put forward the correction, thank you.