Если вы работали с этой платформой более месяца, вы, вероятно, не найдете ничего интересного в этой ретроспективной статье. Ничего, кроме последнего примера в Scala, языка, который случайно отлично работает с Spring.
Сначала был XML [ полный исходный код ]:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<? xml version = "1.0" encoding = "UTF-8" ?> xsi:schemaLocation = "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd " > < bean id = "foo" class = "com.blogspot.nurkiewicz.Foo" > < property name = "bar" ref = "bar" /> < property name = "jdbcOperations" ref = "jdbcTemplate" /> </ bean > < bean id = "bar" class = "com.blogspot.nurkiewicz.Bar" init-method = "init" /> < bean id = "dataSource" class = "org.apache.commons.dbcp.BasicDataSource" > < property name = "driverClassName" value = "org.h2.Driver" /> < property name = "url" value = "jdbc:h2:mem:" /> < property name = "username" value = "sa" /> </ bean > < bean id = "jdbcTemplate" class = "org.springframework.jdbc.core.JdbcTemplate" > < constructor-arg ref = "dataSource" /> </ bean > </ beans > |
Это простое приложение извлекает только время сервера базы данных H2 и печатает его с полным форматированием:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
public class Foo { private Bar bar; private JdbcOperations jdbcOperations; public String serverTime() { return bar.format( jdbcOperations.queryForObject( "SELECT now()" , Date. class ) ); } public void setBar(Bar bar) { this .bar = bar; } public void setJdbcOperations(JdbcOperations jdbcOperations) { this .jdbcOperations = jdbcOperations; } } |
01
02
03
04
05
06
07
08
09
10
11
12
|
public class Bar { private FastDateFormat dateFormat; public void init() { dateFormat = FastDateFormat.getDateTimeInstance(FULL, FULL); } public String format(Date date) { return dateFormat.format(date); } } |
В этом коде есть что-то тревожное. Прежде всего, на удивление много XML. Это все еще меньше по сравнению с аналогичным приложением EJB 2.1 (с небольшими изменениями этот код работает на Spring 1.2.6, начиная с 2006 года), но кажется, что это неправильно. Публичные сеттеры вызывают еще большее беспокойство — почему мы вынуждены предоставлять возможность переопределять зависимости объектов в любое время и кем угодно? Кстати, я так и не понял, почему Spring не позволяет вставлять зависимости напрямую в приватные поля при использовании тега, поскольку это возможно с…
Аннотации [ полный источник ]
В Java 5 и Spring 2.5 появилась поддержка внедрения зависимостей на основе аннотаций:
1
2
3
4
5
|
< context:annotation-config /> <!-- or even: --> < context:component-scan base-package = "com.blogspot.nurkiewicz" /> |
Возьмите первую строку, и вам больше не нужно определять теги <property> в вашем XML, только <bean> s. Фреймворк будет подбирать стандартные аннотации @Resource. Замените его второй строкой, и вам даже не нужно указывать bean-компоненты в вашем XML:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
@Service public class Foo { @Resource private Bar bar; @Resource private JdbcOperations jdbcOperations; public String serverTime() { return bar.format( jdbcOperations.queryForObject( "SELECT now()" , Date. class ) ); } } |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@Service public class Bar { private FastDateFormat dateFormat; @PostConstruct public void init() { dateFormat = FastDateFormat.getDateTimeInstance(FULL, FULL); } public String format(Date date) { return dateFormat.format(date); } } |
Конечно, вы не впечатлены! Нихил нови . Кроме того, нам все еще приходится жить с XML, потому что мы не имеем никакого контроля над сторонними классами (такими как источник данных и JdbcTemplate ), поэтому мы не можем их комментировать. Но Spring 3.0 представил:
@Configuration [ полный источник ]
Я уже изучал поддержку @ Configuration / @ Bean , поэтому на этот раз, пожалуйста, сконцентрируйтесь на том, как мы запускаем контекст приложения. Вы видите какую-либо ссылку на файл XML? Дескриптор applicationContext.xml полностью отсутствует:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
@ComponentScan ( "com.blogspot.nurkiewicz" ) public class Bootstrap { private static final Logger log = LoggerFactory.getLogger(Bootstrap. class ); @Bean public DataSource dataSource() { final BasicDataSource dataSource = new BasicDataSource(); dataSource.setDriverClassName( "org.h2.Driver" ); dataSource.setUrl( "jdbc:h2:mem:" ); dataSource.setUsername( "sa" ); return dataSource; } @Bean public JdbcTemplate jdbcTemplate() { return new JdbcTemplate(dataSource()); } public static void main(String[] args) { final AbstractApplicationContext applicationContext = new AnnotationConfigApplicationContext(Bootstrap. class ); final Foo foo = applicationContext.getBean(Foo. class ); log.info(foo.serverTime()); applicationContext.close(); } } |
Как вы видите, Spring прошел довольно долгий путь от XML-тяжелого фреймворка до XML. Но самое интересное в том, что вы можете использовать любой стиль, который предпочитаете, или даже смешивать их. Вы можете взять унаследованное приложение Spring и начать использовать аннотации или переключиться на XML, чтобы бог знал, по каким причинам здесь или там.
Одна из техник, о которых я не упомянул, — инжекция конструктора Он имеет некоторые большие преимущества (см. Внедрение зависимостей с помощью конструкторов? ), Например, возможность помечать зависимости как окончательные и запрещать создание неинициализированных объектов:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
@Service public class Foo { private final Bar bar; private final JdbcOperations jdbcOperations; @Autowired public Foo(Bar bar, JdbcOperations jdbcOperations) { this .bar = bar; this .jdbcOperations = jdbcOperations; } //... } |
Я хотел бы инъекцию конструктора, однако я снова чувствую себя немного разочарованным. Каждая и каждая объектная зависимость требует (а) параметра конструктора, (б) конечного поля и (в) операции присваивания в конструкторе. В итоге получается десять строк кода, которые еще ничего не делают. Этот болтливый код преодолевает все преимущества. Конечно, ни у одного объекта не должно быть больше (укажите здесь ваш номер) зависимостей — и благодаря внедрению в конструктор вы сразу увидите, что у объекта слишком много — но все же я обнаружил, что этот код вводит слишком много церемоний.
Инжектор Spring в Scala [ полный исходный код ]
Одна особенность Scala идеально вписывается в среду Spring: каждый аргумент любого объекта Scala по умолчанию создает конечное поле с именем, совпадающим с этим аргументом. Что это значит в нашем случае? Посмотрите на класс Foo, переведенный на Scala:
1
2
3
4
5
6
|
@Service class Foo @Autowired () (bar: Bar, jdbcOperations: JdbcOperations) { def serverTime() = bar.format(jdbcOperations.queryForObject( "SELECT now()" , classOf[Date])) } |
Шутки в сторону? Но как? Прежде чем мы углубимся в преимущества Scala, рассмотрим эквивалентный код Java, сгенерированный декомпилятором Java:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
@Service public class Foo implements ScalaObject { private final Bar bar; private final JdbcOperations jdbcOperations; @Autowired public Foo(Bar bar, JdbcOperations jdbcOperations) { this .bar = bar; this .jdbcOperations = jdbcOperations; } public String serverTime() { return this .bar.format( this .jdbcOperations.queryForObject( "SELECT now()" , Date. class )); } } |
Почти точно такой же код, как мы написали бы на Java. Со всеми преимуществами: зависимости окончательно делают наши услуги по-настоящему неизменными и не сохраняющими состояния; зависимости являются частными и не подвержены влиянию внешнего мира; буквально нет лишнего кода для управления зависимостями: просто добавьте аргумент конструктора, Scala позаботится обо всем остальном.
Чтобы обернуть вещи — у вас есть широкий спектр возможностей. От XML, через Java-код до Scala. Последний подход на самом деле очень заманчивый, поскольку он избавляет вас от всего стандартного и позволяет сосредоточиться на функциональности бизнеса. Полный исходный код доступен в моем репозитории GitHub, каждый шаг помечен тегом, чтобы вы могли сравнивать и выбирать тот подход, который вам больше нравится.
Ссылки: Эволюция методов внедрения зависимостей Spring от нашего партнера JCG Томека Нуркевича в NoBlogDefFound
Удачного кодирования! Не забудь поделиться!
Статьи по Теме: