В Spring 3.1 есть способ автоматически заполнять типизированный список, который очень удобен, когда вы хотите немного отменить разделение и очистку в вашем коде.
Чтобы показать вам, как это работает, я реализую простую цепочку ответственности, которая позаботится о печати некоторых поздравлений для прошедшего пользователя.
Давайте начнем с (единственного) класса домена, который у нас есть, Пользователь:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
package com.marco.springchain; public class User { private final String name; private final char gender; public User(String name, char gender) { super (); this .name = name; this .gender = gender; } public String getName() { return name; } public char getGender() { return gender; } } |
Затем мы создаем интерфейс, который определяет тип объектов нашей команды, которые будут использоваться в нашей цепочке:
1
2
3
4
5
|
package com.marco.springchain; public interface Printer { void print(User user); } |
Это универсальный класс (шаблон) для реализации принтера.
org.springframework.core.Ordered
используется, чтобы сообщить AnnotationAwareOrderComparator, как мы хотим, чтобы наш список был упорядочен.
Вам не нужно реализовывать интерфейс Ordered и переопределять метод getOrder, если вам не нужна цепочка для выполнения порядка выполнения.
Также обратите внимание, что этот абстрактный класс возвращает Ordered.LOWEST_PRECEDENCE
, потому что я хочу, чтобы некоторые команды Printer просто выполнялись в конце цепочки, и мне нет дела до их порядка выполнения (все будет ясно после, обещаю!).
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
package com.marco.springchain; import org.springframework.core.Ordered; public abstract class <code>GenericPrinter </code> implements Printer, Ordered { public void print(User user) { String prefix = 'Mr' ; if (user.getGender() == 'F' ) { prefix = 'Mrs' ; } System.out.println(getGreeting() + ' ' + prefix + ' ' + user.getName()); } protected abstract String getGreeting(); public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } } |
Это наша первая настоящая команда Принтер. Я хочу, чтобы это имело абсолютный приоритет в цепочке, поэтому порядок HIGHEST_PRECEDENCE
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
package com.marco.springchain; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; @Component public class HelloPrinter extends GenericPrinter { private static final String GREETING = 'Hello' ; @Override protected String getGreeting() { return GREETING; } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } } |
WelcomePrinter
который будет выполнен как первая команда ( после старших команд).
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
package com.marco.springchain; import org.springframework.stereotype.Component; @Component public class WelcomePrinter extends GenericPrinter { private static final String GREETING = 'Welcome to the autowired chain' ; @Override protected String getGreeting() { return GREETING; } @Override public int getOrder() { return 1 ; } } |
GoodbyePrinter
будет выполняться как вторая команда
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
package com.marco.springchain; import org.springframework.stereotype.Component; @Component public class GoodbyePrinter extends GenericPrinter { private static final String GREETING = 'Goodbye' ; @Override protected String getGreeting() { return GREETING; } @Override public int getOrder() { return 2 ; } } |
Эти 2 команды должны быть выполнены после других, но мне не важен их конкретный порядок, поэтому я не буду переопределять метод getOrder, оставляя GenericPrinter для возврата Ordered.LOWEST_PRECEDENCE
для обоих.
01
02
03
04
05
06
07
08
09
10
11
12
|
package com.marco.springchain; import org.springframework.stereotype.Component; @Component public class CleaningMemoryPrinter extends GenericPrinter { private static final String GREETING = 'Cleaning memory after' ; @Override protected String getGreeting() { return GREETING; } } |
01
02
03
04
05
06
07
08
09
10
11
12
|
package com.marco.springchain; import org.springframework.stereotype.Component; @Component public class CleaningSpacePrinter extends GenericPrinter { private static final String GREETING = 'Cleaning space after' ; @Override protected String getGreeting() { return GREETING; } } |
Это контекст цепочки.
Spring будет сканировать (см. Spring-config.xml) пакет, указанный в файле конфигурации, он увидит типизированный List<Printer>
( List<Printer>
) и заполнит список экземпляром любого @Component
который реализует тип Принтер.
Чтобы упорядочить список, мы используем AnnotationAwareOrderComparator.INSTANCE
который использует метод getOrder для переупорядочения списка ( объект с наименьшим значением имеет наивысший приоритет (в некоторой степени аналогичный значениям «загрузка при запуске» сервлета ) ).
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package com.marco.springchain; import java.util.Collections; import java.util.List; import javax.annotation.PostConstruct; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.stereotype.Component; @Component public class PrinterChain { @Autowired private List<Printer> printers; @PostConstruct public void init() { Collections.sort(printers, AnnotationAwareOrderComparator.INSTANCE); } public void introduceUser(User user) { for (Printer printer : printers) { printer.print(user); } } } |
Spring-config.xml в src / main / resources.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
<?xml version= '1.0' encoding= 'UTF-8' ?> <beans xmlns= 'http://www.springframework.org/schema/beans' xsi:schemaLocation=' http: //www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http: //www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http: //www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd http: //www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd' default-lazy-init='true'> <context:component-scan base- package = 'com.marco.springchain' /> </beans> |
Наконец, основной класс для тестирования нашей цепочки.
01
02
03
04
05
06
07
08
09
10
11
|
package com.marco.springchain; import org.springframework.context.support.ClassPathXmlApplicationContext; public class MainTest { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( 'spring-config.xml' ); PrinterChain printerChain = (PrinterChain) context.getBean( 'printerChain' ); printerChain.introduceUser( new User( 'Marco Castigliego' , 'M' )); printerChain.introduceUser( new User( 'Julie Marot' , 'F' )); } } |
ВЫХОД:
01
02
03
04
05
06
07
08
09
10
|
Hello Mr Marco Castigliego Welcome to the autowired chain Mr Marco Castigliego Goodbye Mr Marco Castigliego Cleaning space after Mr Marco Castigliego Cleaning memory after Mr Marco Castigliego Hello Mrs Julie Marot Welcome to the autowired chain Mrs Julie Marot Goodbye Mrs Julie Marot Cleaning space after Mrs Julie Marot Cleaning memory after Mrs Julie Marot |
Надеюсь, вам понравился пример.
Ссылка: цепь ответственности с использованием Spring @Autowired List от нашего партнера по JCG Марко Кастильего из блога « Удалить дубликаты и исправить дурные имена» .