最近在知乎上面看到一篇關於程序員面試的問題,面試官問我們一般有幾種注入的方法,這幾種注入的方法分別在什么時候運用比合理,當時我看到這個時候懵逼了,由於我自己也是剛剛接觸springboot不久,所以就自己在平時運用的上面總結了一些知識點常用的幾種springboot的注入方法,由於我是一個小萌新,所只要是能夠起道注入的方法的注解我都列出來,有可能會有錯,希望大家能夠及時提出來我來解決:
- @Autowired
- @Resource
- @Component
- @Configuration
- @Qualifie
- @Bean
- ........
這幾種常用的嗎?難道還有什么其他的?當然有,下面我總結了一下自己對於這幾種注入的看法和認識。
首先是我們使用頻率較為高的@Autowired:
這個注解可能是我們使用頻率較為頻繁的一個注解的了,幾乎在剛剛入門的時候,我們都會使用這個注釋,那么@Autowired 注釋的工作原理是什么呢?
第一:其實在啟動spring IoC時,容器自動裝載了一個AutowiredAnnotationBeanPostProcessor后置處理器,當容器掃描到@Autowied、@Resource或@Inject時,就會在IoC容器自動查找需要的bean,並裝配給該對象的屬性
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
第二:@Autowired 注釋,它可以對類成員變量、方法及構造函數進行標注,完成自動裝配的工作。 通過 @Autowired的使用來消除 set ,get方法。在使用@Autowired之前,我們對一個bean配置起屬性時,是這用用的
<property name="屬性名" value=" 屬性值"/>
通過這種方式來,配置比較繁瑣,而且代碼比較多。在Spring 2.5 引入了 @Autowired 注釋
我們平常直接引用的時候很少注意這些,只是自己寫好了一個方法或者springboot自動配置好的一個方法我們要在另一個類中去調用,這個時候,我們就會采用該注釋,例如:我已經寫好一個工具類,此時,我需要在其他類中調用該工具類的方法:
/*
這是要被調用的類
*/
@Repository("userRepository")
public class UserRepositoryImps implements UserRepository{
@Override
public void save() {
System.out.println("UserRepositoryImps save is success");
}
}
已調用的類
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.proc.bean.repository.UserRepository;
/*
方法注入的類
*/
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public void save(){
userRepository.save();
}
}
接着我們開始聊一下@Resource這個注解:
第一:@Resource(這個注解屬於J2EE的),默認按照名稱進行裝配,名稱可以通過name屬性進行指定,如果沒有指定name屬性,當注解寫在字段上時,默認取字段名進行安裝名稱查找,如果注解寫在setter方法上默認取屬性名進行裝配。當找不到與名稱匹配的bean時才按照類型進行裝配。但是需要注意的是,如果name屬性一旦指定,就只會按照名稱進行裝配。
第二:可以用在方法、屬性、類上,通過CommonAnnotationBeanPostProcessor類實現依賴注入 與@AutoWired一致。但可以指定name屬性來指定beanName,但如果name對應的bean不存在,則會拋出異常,且沒有required屬性。
當作用在類上面的時候:可以用來指定name
@Resource(name = "testMapper")
private TestMapper testMapper;
第三:@Autowired默認按類型裝配(這個注解是屬業spring的),默認情況下必須要求依賴對象必須存在,如果要允許null 值,可以設置它的required屬性為false
@Autowired()
private StudentDao studentDao;
來,繼續往下走,開始擼@Component這個注解:
第一:@Component泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注。
第二:@component (把普通pojo實例化到spring容器中,相當於配置文件中的<bean id="" class=""/>
)泛指各種組件,就是說當我們的類不屬於各種歸類的時候(不屬於@Controller、@Services等的時候),我們就可以使用@Component來標注這個類。
例如下面的這個例子
注意:這個只能作用於類上面
package cn.com.scitc.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component("myLoginSuccessHandler")
public class MyLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private ObjectMapper objectMapper;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException {
response.setContentType("application/json;charset=UTF-8");
logger.info("登錄成功");
PrintWriter out = response.getWriter();
out.write(objectMapper.writeValueAsString("登錄成功"));
out.flush();
out.close();
}
}
看了這么多,是不是有點累了,不行接着擼@Configuration的注解:
首先我們先明白從Spring3.0,@Configuration用於定義配置類,可替換xml配置文件,被注解的類內部包含有一個或多個被@Bean注解的方法,這些方法將會被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext類進行掃描,並用於構建bean定義,初始化Spring容器。
在使用的時候需要注意:
1.@Configuration不可以是final類型;
2.@Configuration不可以是匿名類;
3.嵌套的configuration必須是靜態類。
下面講解詳細的使用
第一:用@Configuration加載spring
1.1、@Configuration配置spring並啟動spring容器
1.2、@Configuration啟動容器+@Bean注冊Bean
1.3、@Configuration啟動容器+@Component注冊Bean
1.4、使用 AnnotationConfigApplicationContext 注冊 AppContext 類的兩種方法
1.5、配置Web應用程序(web.xml中配置AnnotationConfigApplicationContext)
第二:組合多個配置類
2.1、在@configuration中引入spring的xml配置文件
2.2、在@configuration中引入其它注解配置
2.3、@configuration嵌套(嵌套的Configuration必須是靜態類)
2.4、@EnableXXX注解
2.5、@Profile邏輯組配置
2.6、使用外部變量
下面講解一個比較常用的例子:不知道各位大佬的在用在SpringBoot 中使用Security安全框架的時候會出現一個默認的登錄界面,但是我們一般不回去用哪個登錄界面,這時候我們就應該自己去寫一個登錄的界面以及后端的實行方法,那么這個時候,@configuration就派上用場了,話不多說,直接上例子:
package cn.com.scitc.config;
import org.springframework.boot.web.server.ConfigurableWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
@Configuration
public class ErrorConfigurar {
/**
* 自定義錯誤頁面
* @return
*/
@Bean
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer() {
return (factory -> {
ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/404");
ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,"/500");
ErrorPage errorPage403 = new ErrorPage(HttpStatus.FORBIDDEN,"/403");
factory.addErrorPages(errorPage404);
factory.addErrorPages(errorPage403);
factory.addErrorPages(errorPage500);
});
}
}
注意:該注釋也是用於全局的,所以定義在類上面。
接下來來一個就比較簡單的@Qualifier了,這個注解在我認為就是@Autowired的小弟,它一般和@Autowired一起用,當 @Autowired() 不帶參數的時候@Qualifie就可以帶上參數。Qualifier限定描述符除了能根據名字進行注入,更能進行更細粒度的控制如何選擇候選者。
@Autowired()
@Qualifie("/studentDao")
private StudentDao studentDao;
現在繼續擼一個叫@Bean的注解;
很多人就會問@Bean為什么可以當做注入來用呢?在剛剛開始的時候我也是認為@Bean就是封裝一個POJO類而已,可是后面我覺得它是可以用來當做注入注解來使用的。
首先,@Bean可理解為用spring的時候xml里面的<bean>
標簽;
其次,@Bean是一個方法級別上的注解,主要用在@Configuration注解的類里,也可以用在@Component注解的類里,添加的bean的id為方法名;
@Configuration
public class AppConfig {
@Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
再接着:@bean 也可以依賴其他任意數量的bean,如果TransferService 依賴 AccountRepository,我們可以通過方法參數實現這個依賴;
@Bean
public TransferService transferService(AccountRepository accountRepository) {
return new TransferServiceImpl(accountRepository);
}
最后講一下,指定bean的scope
使用@Scope注解來指定使用@Bean定義的bean
@Scope("prototype")
設置@Scope的屬性proxyMode
來指定,默認是ScopedProxyMode.NO
, 你可以指定為默認是ScopedProxyMode.INTERFACES
或者默認是ScopedProxyMode.TARGET_CLASS
。
@Bean
@SessionScope
public StuPreferences stuPreferences() {
return new StuPreferences();
}
@Bean
public Service StuService() {
StuService service = new SimpleStuService();
service.setStuPreferences(StuPreferences());
return service;
}
通過上面的說明,就足以說明這是可以用來注入的。
最后,我們來探討一下private final
修飾的變量可以被用來作為注入你們覺得可以嗎?
試想,在一個大的項目中,幾乎所有的引用都是用public、@Bean等相應的方法注入,那么就會造成代碼的耦合度較高,造成了項目的維護困難,那么久只有被項目經理K一頓啦。
最后,由於我是小萌新一個,有總結不到位的,或者錯誤的,希望各位大佬指正出來。小弟感激不盡。