Насколько я знаю, 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; @Service class 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; @Service public 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 @EnableAutoConfiguration public 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 Любоса Крнака в |