SpringBean的生命周期
??有關(guān)Bean的生命周要從他們的作用域來區(qū)分。所謂的生命周期就是從 創(chuàng)建->使用->銷毀
??singlton(單例):從Spring 容器的創(chuàng)建到Spring容器的銷毀。(如果是延時加載,在對象使用前創(chuàng)建對象。)
??prototype(原型):在調(diào)用前創(chuàng)建,使用后銷毀。
SpringBean是線程安全的嗎,其作用域是什么?
在 Spring 中注入一個 Java 集合
Spring 提供了以下四種集合類的配置元素:
1: 該標(biāo)簽用來裝配可重復(fù)的 list 值。
2: 該標(biāo)簽用來裝配沒有重復(fù)的 set 值。
3: 該標(biāo)簽可用來注入鍵和值可以為任何類型的鍵值對。
4: 該標(biāo)簽支持注入鍵和值都是字符串類型的鍵值對。
<beans>
<!-- Definition for javaCollection -->
<bean id="javaCollection" class="com.gupaoedu.JavaCollection">
<!-- java.util.List -->
<property name="customList">
<list>
<value>INDIA</value>
<value>Pakistan</value>
<value>USA</value>
<value>UK</value>
</list>
</property>
<!-- java.util.Set -->
<property name="customSet">
<set>
<value>INDIA</value>
<value>Pakistan</value>
<value>USA</value>
<value>UK</value>
</set>
</property>
<!-- java.util.Map -->
<property name="customMap">
<map>
<entry key="1" value="INDIA"/>
<entry key="2" value="Pakistan"/>
<entry key="3" value="USA"/>
<entry key="4" value="UK"/>
</map>
</property>
<!-- java.util.Properties -->
<property name="customProperies">
<props>
<prop key="admin">admin@gupaoedu.com</prop>
<prop key="support">support@gupaoedu.com</prop>
</props>
</property>
</bean>
</beans>
Spring的五種裝配方式
??no:這是 Spring 框架的默認(rèn)設(shè)置,在該設(shè)置下自動裝配是關(guān)閉的,開發(fā)者需要自行在 bean 定義中用標(biāo)簽明確的設(shè)置依賴關(guān)系。
??byName:該選項(xiàng)可以根據(jù) bean名稱設(shè)置依賴關(guān)系。當(dāng)向一個 bean中自動裝配一個屬性時,IOC容器將根據(jù) bean 的名稱自動在對應(yīng)的容器中獲取,如果找到就返回,沒有找到就報(bào)錯。
??byType:該選項(xiàng)可以根據(jù) bean 類型設(shè)置依賴關(guān)系。當(dāng)向一個 bean中自動裝配一個屬性時,IOC容器將根據(jù) bean 的名稱自動在對應(yīng)的容器中獲取,如果找到就返回,沒有找到就報(bào)錯。
??constructor:構(gòu)造器的自動裝配和 byType 模式類似,但是僅僅適用于與有構(gòu)造器相同參數(shù)的 bean,如果在容器中沒有找到與構(gòu)造器參數(shù)類型一致的 bean,那么將會拋出異常。
??autodetect:該模式自動探測使用構(gòu)造器自動裝配或者 byType 自動裝配。首先,首先會嘗試找合適的帶參數(shù)的構(gòu)造器,如果找到的話就是用構(gòu)造器自動裝配,如果在 bean 內(nèi)部沒有找到相應(yīng)的構(gòu) 造器或者是無參構(gòu)造器,容器就會自動選擇 byTpe 的自動裝配方式。
如何開啟基于注解的自動裝配?
??1.引入配置文件中的下引入
<beans>
<context:annotation-config />
</beans>
??在 bean 配置文件中直接引入 AutowiredAnnotationBeanPostProcessor
<beans>
<bean
class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProc
essor"/>
</beans>
自動裝配有哪些局限性?
??重寫:你仍然需要使用 和< property>設(shè)置指明依賴,這意味著總要重寫自動裝配。
??原生數(shù)據(jù)類型:你不能自動裝配簡單的屬性,如原生類型、字符串和類。
??模糊特性:自動裝配總是沒有自定義裝配精確,因此,如果可能盡量使用自定義裝配。
請舉例解釋@Required 注入
??主要用于校驗(yàn)?zāi)硞€bean的特定屬性是否被正確的設(shè)置。如下:
public class EmployeeFactoryBean extends AbstractFactoryBean<Object>{
private String designation;
public String getDesignation() {
return designation;
}
@Required
public void setDesignation(String designation) {
this.designation = designation;
}
}
??RequiredAnnotationBeanPostProcessor 是 Spring 中的后置處理用來驗(yàn)證被@Required 注解的 bean 屬性是否被正確的設(shè)置了。如果沒有找到對應(yīng)的配置則會拋出BeanInitializationException
異常。
設(shè)置注入和構(gòu)造注入
區(qū)別:注入的順序、注入的時機(jī)、注入的有限性、循環(huán)依賴等問題。
??1.在設(shè)值注入方法支持大部分的依賴注入,如果我們僅需要注入int、string和long型的變量,我們不要用設(shè)值的方法注入。對于基本類型,如果我們沒有注入的話,可以為基本類型設(shè)置默認(rèn)值。
??在構(gòu)造方法注入不支持大部分的依賴注入,因?yàn)樵谡{(diào)用構(gòu)造方法中必須傳入正確的構(gòu)造參數(shù),否則的話為報(bào)錯。
??2.設(shè)值注入不會重寫構(gòu)造方法的值。如果我們對同一個變量同時使用了構(gòu)造方法注入又使用了設(shè)置方法注入的話,那么構(gòu)造方法將不能覆蓋由設(shè)值方法注入的值。很明顯,因?yàn)闃?gòu)造方法盡在對象被創(chuàng)建時調(diào)用。
??3.在使用設(shè)值注入時有可能還不能保證某種依賴是否已經(jīng)被注入,也就是說這時對象的依賴關(guān)系有可能是不完整的。而在另一種情況下,構(gòu)造器注入則不允許生成依賴關(guān)系不完整的對象。
??4.在設(shè)值注入時如果對象A和對象B互相依賴,在創(chuàng)建對象A時Spring會拋出ObjectCurrentlyInCreationException異常,因?yàn)樵贐對象被創(chuàng)建之前A對象是不能被創(chuàng)建的,反之亦然。所以Spring用設(shè)值注入的方法解決了循環(huán)依賴的問題,因?qū)ο蟮脑O(shè)值方法是在對象被創(chuàng)建之前被調(diào)用的。
Spring 框架中有哪些不同類型的事件?
??五種:ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、ContextClosedEvent、RequestHandledEvent。
ContextRefreshedEvent
??該事件會在 ApplicationContext 被初始化或者更新時發(fā)布。也可以在調(diào)用 ConfigurableApplicationContext 接口中的 refresh()方法時被觸發(fā)。
ContextStartedEvent
??當(dāng)容器調(diào)用 ConfigurableApplicationContext的Start()方法開始/重新開始容器時觸發(fā)該事件。
ContextStoppedEvent
??當(dāng)容器調(diào)用 ConfigurableApplicationContext的Stop()方法停止容器時觸發(fā)該事件。
ContextClosedEvent
??當(dāng) ApplicationContext 被關(guān)閉時觸發(fā)該事件。容器被關(guān)閉時,其管理的所有單例 Bean 都被銷毀。
RequestHandledEvent
??在 Web 應(yīng)用中,當(dāng)一個 http 請求(request結(jié)束觸發(fā)該事件)
還可以通過擴(kuò)展 ApplicationEvent 類來開發(fā)自定義的事件。
定義
public class CustomApplicationEvent extends ApplicationEvent{
public CustomApplicationEvent ( Object source, final String msg ){
super(source);
System.out.println("Created a Custom event");
}
}
監(jiān)聽
public class CustomEventListener implements ApplicationListener <
CustomApplicationEvent >{
@Override
public void onApplicationEvent(CustomApplicationEvent applicationEvent) {
//handle event
}
}
發(fā)布
CustomApplicationEvent customEvent = new CustomApplicationEvent(applicationContext,
“Test message”);
applicationContext.publishEvent(customEvent);
FileSystemResource 、 ClassPathResource 、ServletContextResource有何區(qū)別?
FileSystemResource
??FileSystemResource 是 Spring 提供的資源訪問類。FileSystemResource 類相比其他兩個資源訪問類,沒有什么優(yōu)勢,它只是在 File 類的基礎(chǔ)上略作封裝。
/*默認(rèn)從文件系統(tǒng)的當(dāng)前路徑加載xttblog.xml資源*/
FileSystemResource fsr = new FileSystemResource("xttblog.xml");
類圖
部分源碼
public class FileSystemResource extends AbstractResource implements WritableResource {
private final File file;
private final String path;
public FileSystemResource(File file) {
Assert.notNull(file, "File must not be null");
this.file = file;
this.path = StringUtils.cleanPath(file.getPath());
}
public FileSystemResource(String path) {
Assert.notNull(path, "Path must not be null");
this.file = new File(path);
this.path = StringUtils.cleanPath(path);
}
/**
* Return the file path for this resource.
*/
public final String getPath() {
return this.path;
}
/**
* This implementation returns whether the underlying file exists.
* @see java.io.File#exists()
*/
@Override
public boolean exists() {
return this.file.exists();
}
.....
}
??FileSystemResource 可以看出有兩種構(gòu)造,一種是文件,一種是字符串。
ClassPathResource
??利用ClassPathResource讀取xml配置的基本思路就是通過構(gòu)造函數(shù)傳入的文件路徑,接著交給class或者classLoader,調(diào)用getResourceAsStream獲取到InputStream。
FileSystemResource 和 ClassPathResource 的用法如下:
public class Test {
String filePath = "D:/com/xttblog.txt";
//使用系統(tǒng)文件路徑方式加載文件
Resource res1 = new FileSystemResource(filePath);
//使用類路徑方式加載文件
Resource res2 = new ClassPathResource("conf/xttblog.txt");
InputStream ins1 = res1.getInputStream();
InputStream ins2 = res2.getInputStream();
getFileName();//獲取文件名
getFile();//獲取資源對應(yīng)的File對象
getInputStream();//獲取文件的輸入流
createRelative(String relativePath);//在相對地址創(chuàng)建新文件
EncodedResource encRes = new EncodedResource(res, "UTF-8");
String content = FileCopyUtils.copyToString(encRes.getReader());
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource resources[] = resolver.getResources("classpath*://com/***/*.xml");
For(Resource resource : resources){
System.out.println(resource.getDescription);
}
}
類圖
源碼
public class ClassPathResource extends AbstractFileResolvingResource {
private final String path;
@Nullable
private ClassLoader classLoader;
@Nullable
private Class<?> clazz;
public ClassPathResource(String path) {
this(path, (ClassLoader) null);
}
public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
String pathToUse = StringUtils.cleanPath(path);
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
this.path = pathToUse;
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
}
public ClassPathResource(String path, @Nullable Class<?> clazz) {
Assert.notNull(path, "Path must not be null");
this.path = StringUtils.cleanPath(path);
this.clazz = clazz;
}
@Deprecated
protected ClassPathResource(String path, @Nullable ClassLoader classLoader, @Nullable Class<?> clazz) {
this.path = StringUtils.cleanPath(path);
this.classLoader = classLoader;
this.clazz = clazz;
}
/**
* Return the path for this resource (as resource path within the class path).
*/
public final String getPath() {
return this.path;
}
/**
* Return the ClassLoader that this resource will be obtained from.
*/
@Nullable
public final ClassLoader getClassLoader() {
return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader);
}
@Override
public boolean exists() {
return (resolveURL() != null);
}
@Nullable
protected URL resolveURL() {
if (this.clazz != null) {
return this.clazz.getResource(this.path);
}
else if (this.classLoader != null) {
return this.classLoader.getResource(this.path);
}
else {
return ClassLoader.getSystemResource(this.path);
}
}
@Override
public InputStream getInputStream() throws IOException {
InputStream is;
if (this.clazz != null) {
is = this.clazz.getResourceAsStream(this.path);
}
else if (this.classLoader != null) {
is = this.classLoader.getResourceAsStream(this.path);
}
else {
is = ClassLoader.getSystemResourceAsStream(this.path);
}
if (is == null) {
throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
}
return is;
}
@Override
public URL getURL() throws IOException {
URL url = resolveURL();
if (url == null) {
throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");
}
return url;
}
@Override
public Resource createRelative(String relativePath) {
String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
return (this.clazz != null ? new ClassPathResource(pathToUse, this.clazz) :
new ClassPathResource(pathToUse, this.classLoader));
}
@Override
@Nullable
public String getFilename() {
return StringUtils.getFilename(this.path);
}
@Override
public String getDescription() {
StringBuilder builder = new StringBuilder("class path resource [");
String pathToUse = path;
if (this.clazz != null && !pathToUse.startsWith("/")) {
builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));
builder.append('/');
}
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
builder.append(pathToUse);
builder.append(']');
return builder.toString();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof ClassPathResource) {
ClassPathResource otherRes = (ClassPathResource) obj;
return (this.path.equals(otherRes.path) &&
ObjectUtils.nullSafeEquals(this.classLoader, otherRes.classLoader) &&
ObjectUtils.nullSafeEquals(this.clazz, otherRes.clazz));
}
return false;
}
@Override
public int hashCode() {
return this.path.hashCode();
}
}
區(qū)別如下:
ClassPathResource:從系統(tǒng)的類路徑中加載
FileSystemResource:從文件系統(tǒng)加載,比如說自己指定配置文件的全路徑
InputStreamResource:從輸入流中加載
ServletContextResource:從Servlet 上下文環(huán)境中加載
UrlResource:從指定的Url加載
Class.getResource("")獲取的是相對于當(dāng)前類的相對路徑。Class.getResource("/")獲取的是classpath的根路徑。ClassLoader.getResource("")獲取的是classpath的根路徑。
在創(chuàng)建ClassPathResource對象時,我們可以指定是按Class的相對路徑獲取文件還是按ClassLoader來獲取。
FileSystemResource 效果類似于Java中的File
ClassPathResource 效果類似于this.getClass().getResource("/").getPath();
ServletContextResource 效果類似于request.getServletContext().getRealPath("");
Spring 框架中都用到了哪些設(shè)計(jì)模式?
很多很多很多
1、代理模式:在 AOP 和 remoting 中被用的比較多。
2、單例模式:在 spring 配置文件中定義的 bean 默認(rèn)為單例模式。
3、模板模式:用來解決代碼重復(fù)的問題。比如. RestTemplate, JmsTemplate, JpaTemplate。
4、委派模式:Spring 提供了 DispatcherServlet 來對請求進(jìn)行分發(fā)。
5、工廠模式:BeanFactory 用來創(chuàng)建對象的實(shí)例,貫穿于 BeanFactory / ApplicationContext
接口的核心理念。
6、代理模式:AOP 思想的底層實(shí)現(xiàn)技術(shù),Spring 中采用 JDK Proxy 和 CgLib 類庫。
Spring5 新特性
1、依賴 JDK 8+和 Java EE7+以上版本
2、首次采用反應(yīng)式編程模型
3、支持使用注解進(jìn)行編程
4、新增函數(shù)式編程
5、支持使用 REST 斷點(diǎn)執(zhí)行反應(yīng)式編程
6、支持 HTTP 2.0
7、新增 Kotlin 和 Spring WebFlux
8、可使用 Lambda 表達(dá)式注冊 Bean
9、Spring WebMVC 支持最新的 API
10、使用 JUnit5 執(zhí)行條件和并發(fā)測試
11、使用 Spring WebFlux 執(zhí)行集成測試
12、核心容器優(yōu)化