接上一篇《Spring4新特性——泛型限定式依賴注入》,接下來(lái)我們看看Spring4的其他改進(jìn)。
1,、Map依賴注入:
- @Autowired
- private Map<String, BaseService> map;
這樣會(huì)注入:key是bean名字,;value就是所有實(shí)現(xiàn)了BaseService的Bean,,假設(shè)使用上一篇的例子,,則會(huì)得到:
{organizationService=com.sishuok.spring4.service.OrganizationService@617029,
userService=com.sishuok.spring4.service.UserService@10ac73b}
2,、List/數(shù)組注入:
- @Autowired
- private List<BaseService> list;
這樣會(huì)注入所有實(shí)現(xiàn)了BaseService的Bean,;但是順序是不確定的,,如果我們想要按照某個(gè)順序獲取,;在Spring4中可以使用@Order或?qū)崿F(xiàn)Ordered接口來(lái)實(shí)現(xiàn),,如:
- @Order(value = 1)
- @Service
- public class UserService extends BaseService<User> {
- }
這種方式在一些需要多態(tài)的場(chǎng)景下是非常有用的。
3,、@Lazy可以延遲依賴注入:
- @Lazy
- @Service
- public class UserService extends BaseService<User> {
- }
- @Lazy
- @Autowired
- private UserService userService;
我們可以把@Lazy放在@Autowired之上,,即依賴注入也是延遲的;當(dāng)我們調(diào)用userService時(shí)才會(huì)注入,。即延遲依賴注入到使用時(shí),。同樣適用于@Bean。
4,、@Conditional
@Conditional類似于@Profile(一般用于如我們有開(kāi)發(fā)環(huán)境,、測(cè)試環(huán)境、正式機(jī)環(huán)境,,為了方便切換不同的環(huán)境可以使用 @Profile指定各個(gè)環(huán)境的配置,,然后通過(guò)某個(gè)配置來(lái)開(kāi)啟某一個(gè)環(huán)境,方便切換) ,,但是@Conditional的優(yōu)點(diǎn)是允許自己定義規(guī)則,。可以指定在如@Component、@Bean,、@Configuration等注解的類上,,以絕對(duì)Bean是否創(chuàng)建等。首先來(lái)看看使用@Profile的用例,,假設(shè)我們有個(gè)用戶模塊:
1,、在測(cè)試/開(kāi)發(fā)期間調(diào)用本機(jī)的模擬接口方便開(kāi)發(fā);
2,、在部署到正式機(jī)時(shí)換成調(diào)用遠(yuǎn)程接口,;
- public abstract class UserService extends BaseService<User> {
- }
-
- @Profile("local")
- @Service
- public class LocalUserService extends UserService {
- }
-
- @Profile("remote")
- @Service
- public class RemoteUserService extends UserService {
- }
我們?cè)趯?xiě)測(cè)試用例時(shí),可以指定我們使用哪個(gè)Profile:
- @ActiveProfiles("remote")
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration(locations = "classpath:spring-config.xml")
- public class ServiceTest {
-
- @Autowired
- private UserService userService;
- }
這種方式非常簡(jiǎn)單,。如果想自定義如@Profile之類的注解等,,那么@Conditional就派上用場(chǎng)了;假設(shè)我們系統(tǒng)中有好多本地/遠(yuǎn)程接口,,那么我們定義兩個(gè)注解@Local和@Remote注解要比使用@Profile方便的多,;如:
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.TYPE, ElementType.METHOD})
- @Conditional(CustomCondition.class)
- public @interface Local {
- }
-
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.TYPE, ElementType.METHOD})
- @Conditional(CustomCondition.class)
- public @interface Remote {
- }
- public class CustomCondition implements Condition {
-
- @Override
- public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
- boolean isLocalBean = metadata.isAnnotated("com.sishuok.spring4.annotation.Local");
- boolean isRemoteBean = metadata.isAnnotated("com.sishuok.spring4.annotation.Remote");
-
- if(!isLocalBean && !isRemoteBean) {
- return true;
- }
-
- boolean isLocalProfile = context.getEnvironment().acceptsProfiles("local");
-
-
- if(isLocalProfile) {
- return isLocalBean;
- }
-
-
- return isRemoteBean;
- }
- }
然后我們使用這兩個(gè)注解分別注解我們的Service:
- @Local
- @Service
- public class LocalUserService extends UserService {
- }
- @Remote
- @Service
- public class RemoteUserService extends UserService {
- }
首先在@Local和@Remote注解上使用@Conditional(CustomCondition.class)指定條件,,然后使用
@Local和@Remote注解我們的Service,,這樣當(dāng)加載Service時(shí),會(huì)先執(zhí)行條件然后判斷是否加載為Bean,。@Profile就是這
樣實(shí)現(xiàn)的,,其Condition
是:org.springframework.context.annotation.ProfileCondition??梢匀タ聪略创a,,很簡(jiǎn)單。
5,、基于CGLIB的類代理不再要求類必須有空參構(gòu)造器了:
這是一個(gè)很好的特性,,使用構(gòu)造器注入有很多好處,,比如可以只在創(chuàng)建Bean時(shí)注入依賴,,然后就不變了,如果使用setter注入,,是允許別人改的,。當(dāng)然我們可以使用spring的字段級(jí)別注入。如果大家使用過(guò)如Shiro,,我們可能要對(duì)Controller加代理,。如果是類級(jí)別代理,此時(shí)要求Controller必須有空參構(gòu)造器,有時(shí)候挺煩人的,。spring如何實(shí)現(xiàn)的呢,?其內(nèi)聯(lián)了objenesis類庫(kù),通過(guò)它來(lái)實(shí)現(xiàn),,可以去其官網(wǎng)看看介紹,。這樣就支持如下方式的構(gòu)造器注入了:
- @Controller
- public class UserController {
- private UserService userService;
- @Autowired
- public UserController(UserService userService) {
- this.userService = userService;
- }
- }
org.springframework.cglib.proxy.Enhancer在其github和maven倉(cāng)庫(kù)中的source中竟然木有,其github:https://github.com/spring-projects/spring-framework/tree/master/spring-core/src/main/java/org/springframework/cglib,;難道忘了嗎,?
|