Насколько я знаю, Spring Framework не предоставляет никакого механизма для инкапсуляции компонентов Spring, кроме как в отдельных контекстах. Поэтому, если у вас есть открытый класс, зарегистрированный в контейнере Spring Inversion of Control, он может быть автоматически подключен к любому бину Spring из той же конфигурации контекста. Это очень сильно, но это также очень опасно. Разработчики могут легко соединить бобы вместе. При отсутствии дисциплины команда может легко выстрелить себе в ногу. К сожалению, я работал над одним монолитным проектом, где команда стреляла в себя из пистолета-пулемета. Проводка часто нарушала правила наслоения. Никто не может легко понять, что зависит от чего. График зависимости бина был просто сумасшедшим. Это серьезная проблема в больших приложениях.
К счастью, есть один простой способ инкапсуляции Spring bean. Spring прекрасно работает с модификатором доступа по умолчанию на уровне класса. Таким образом, вы можете создать пакет bean-компонента, который может использоваться только в текущем пакете. Просто и мощно. Давайте посмотрим на пример:
|
01
02
03
04
05
06
07
08
09
10
|
package net.lkrnac.blog.spring.encapsulatebean.service;import org.springframework.stereotype.Service;@Serviceclass AddressService { public String getAddress(String userName){ return "3 Dark Corner"; }} |
Этот простой bean-компонент подключен к другому пакету:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
package net.lkrnac.blog.spring.encapsulatebean.service;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class UserService { private AddressService addressService; @Autowired public UserService(AddressService addressService) { this.addressService = addressService; } public String getUserDetails(String userName){ String address = addressService.getAddress(userName); return String.format("User: %s, %s", userName, address); }} |
Основной контекст просто сканирует оба бина:
|
01
02
03
04
05
06
07
08
09
10
11
12
|
package net.lkrnac.blog.spring.encapsulatebean;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;@Configuration@ComponentScan@EnableAutoConfigurationpublic class Application {} |
Вот тест, чтобы доказать, что он работает нормально:
|
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
|
package net.lkrnac.blog.spring.encapsulatebean;import net.lkrnac.blog.spring.encapsulatebean.service.UserService;import org.junit.Assert;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.SpringApplicationConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;@RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(classes = Application.class)public class ApplicationTests { @Autowired private UserService userService; @Test public void isPackagePrivateBeanCalled(){ //GIVEN - spring context defined by Application class //WHEN String actualUserDetails = userService.getUserDetails("john"); //THEN Assert.assertEquals("User: john, 3 Dark Corner", actualUserDetails); }} |
Я считаю, что все должны рассмотреть возможность использования модификатора доступа по умолчанию для каждого нового компонента. Очевидно, что в каждом пакете должен быть какой-то общедоступный компонент. Но не на каждом бобе. Исходный код есть на GitHub .
| Ссылка: | Как инкапсулировать Spring bean от нашего партнера JCG Любоса Крнака в |