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.