SpringIoc的了解
1、概念:控制反轉(Inversion of Control),是面向對象程式設計中的一種設計原則,可以用來降低計算機代碼之間的耦合度。最常見的實作方式叫做依賴注入(Dependency Injection),還有一種方式叫“依賴查找”(Dependency lookup)。Ioc控制反轉是指将由我們控制的建立對象及擷取依賴對象,交給IOC容器控制,由容器幫我們建立對象并關注依賴對象,控制對外部資源的擷取。
2、使用Ioc的原因:在程式開發過程中,使用面向抽象程式設計,面向抽象程式設計會産生類的依賴,spring為我們提供了管理的容器,即Ioc。有了管理容器後,類的産生過程交給了容器,我們就不用關心對象的産生了。
3、Ioc實作的思路和方法:首先需要提供一些配置資訊用來描述類之間的關系,然後由容器去解析這些配置資訊,繼而維護好對象之間的依賴關系,前提是對象間的依賴關系必須在類中定義好。比如A.class中有一個B.class屬性,那麼可以了解為A依賴了B。
大緻可分為3點:①應用程式中提供類,提供依賴關系(屬性或構造方法)。②把需要交給容器管理的對象通過配置資訊告訴容器。③把各類之間的依賴關系通過配置資訊告訴容器。
4、spring的程式設計風格(可混合使用)
①schema-based XML方式
②Annotation-based 注解方式(需要結合xml方式或javaconfig方式使用,開啟和掃描注解)
③java-based javaconfig方式(使用時需要建立配置類@Configuration,可通過@ImportResource(xml檔案)來加入xml配置檔案)
注意:前兩種方式通過ClassPathXMLApplicationContext解析,javaconfig通過AnnotationConfigApplicationContext解析。
5、Spring對象注入方法
①Constructor-based DI 構造方法注入
②setter-based DI set方法注入
spring3以前還提供了接口注入,但是spring4以後已經不再使用。注意使用XML注入時的p空間注入(p:name)和c空間注入(c:name)。
6、自動裝配:隻需在類中定義對象的依賴關系,而不需要在spring中配置依賴關系,這就是通過自動裝配來實作。
自動裝配方法:
①no 不自動裝配,需要提供對象間依賴的配置(預設方法)
②byType 按類型裝配
③byName 按名稱裝配
④constructor 類似于byType ,但适用于構造函數參數,容器中不能有多個構造函數
XML方式:在< beans >标簽中加入default-autowire=類型,來指定自動裝配的方法,也可以對某個< bean >單獨指定自動裝配方法。需要注意的是按名稱裝配時,名稱與set方法的值關聯。
注解方式:使用@Autowired注解或@Resource注解。
@Autowired和@Resource差別:它們都可以用來自動裝配bean,都可以寫在字段上或setter方法上。@Autowired屬于spring,預設按類型裝配,如果沒有找到才會按名稱查找,預設是必須存在的,可以通過required屬性改為false,即可允許null值。指定按名稱裝配可以結合@Qualifier注解進行使用。@Resource屬于J2EE,預設按照名稱裝配,名稱可通過name屬性進行指定,如果沒指定name屬性,當注解寫在屬性上時,預設取屬性名進行查找,如果注解寫在setter方法上時,預設取setter方法中set後的值第一個字母小寫進行裝配。當找不到名稱比對的bean時,才會按照類型進行裝配。但name或type屬性一旦指定,必須按照對應值裝配,找不到則報錯。用名稱裝配速度更快。
7、spring懶加載
在第一次請求時,Ioc容器才執行個體化Bean,而不是在初始化時就建立。xml中全局設定為懶加載,即在< beans >标簽中增加屬性default-lazy-init=true;給某個bean設定為懶加載,則在< bean >标簽中增加屬性lazy-init=true。注解和javaconfig方式在對應類中加入@Lazy注解即可實作懶加載。
8、spring的Bean作用域
注解@Scope。
singlton 單例,每次通路都是同一個Bean對象(spring中預設)
prototype 原型,每次通路都是新的Bean對象
request
session
application
websocket
注意問題:
Singleton Beans with Prototype-bean Dependencies:在Singleton 當中引用了一個Prototype的bean,會造成Prototype作用域的bean也隻能使用一個bean對象。
解決方法:
①實作ApplicationContextAware接口,重寫setApplicationContext()方法擷取ApplicationContext對象,通過此對象getBean擷取Prototype作用域的bean。
②使用@Lookup(bean名)注解(在XML中可以使用< lookup-method >标簽)查找Prototype作用域的bean,這時就不需要自動裝配。
例:@Lookup(“dao”)
public abstract Dao getDao();
通過 getDao()即可擷取bean對象。
9、spring生命周期的回調
①Initialization callbacks 初始化回調
實作InitializingBean接口,重寫afterPropertiesSet方法,該方法會在對象建立後初始化時調用。
Destruction callbacks 銷毀回調
實作DisposableBean接口,重寫destroy()方法,該方法在對象銷毀時調用。
②Default Initialization and Destroy Methods 預設的初始化和銷毀方法
在XML配置中,增加< beans > 标簽的default-init-method=‘方法名’或default-init-destroy=‘方法名’屬性,在對應類中重寫方法名方法即可。
③@Postconstruct和@Predestroy注解,分别表示初始化時調用方法和銷毀時調用方法。
10、spring其他常用注解
①@ComponentScan:用于掃描檔案
②@Primary:在多個對象進行選擇時使用,當有多個資料源時,設為主源,spring在讀取時會優先選擇這個注解标記的類。如@Autowired裝配Bean時,有多個相同類型Bean,可以設定其中一個為主類,spring會使用此類進行裝配。
③@Profile:用于環境切換,在對應環境下生效。可以用于切換某個bean,也可以用于切換整個配置檔案。
例:
public static void main(String[] args) {
AnnotationConfigApplicationContext annotationConfigApplicationContext
= new AnnotationConfigApplicationContext();
//切換到@Profile的環境
annotationConfigApplicationContext.getEnvironment().setActiveProfiles("@Profile的名字");
annotationConfigApplicationContext.register(AppConfig.class);
annotationConfigApplicationContext.refresh();
TestService service = annotationConfigApplicationContext.getBean(TestService.class);
System.out.println(service.getName());
}
④@Bean依賴,可以作為參數傳入到方法中
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
//或者直接使用方法引入
//sqlSessionFactoryBean.setDataSource(dataSource());
return sqlSessionFactoryBean;
}
@Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setPassword("root");
dataSource.setUsername("root");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3308/turtle?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC");
return dataSource;
}
⑤@Component是@Service,@Repository和@Controller的父類,後面的注解隻是将功能細分,友善查找管理。spring文檔上提示将來可能會增加另外的含義,是以我們使用時最好按功能使用不同注解。
⑥可以用java注解代替spring注解使用。如@Inject代替@Autowired;@Named代替@Component;@Singleton代替@Scope(“singleton”)等。但都有局限性,如下表(來自官方文檔)。
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHLxsmaNJTWU5UMNpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL0MTO4QTO0ETM4EjNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
11、自定義注解
注解:描述資料的資料。可以在編譯類加載、運作時被讀取。
分類:
内建注解,标準注解類型。如:@Override,@SuppressWarnings等
元注解,修飾注解的注解。如:@Target(用于指定注解可使用的位置),@Retention(用于标注注解存活時間的長短)等
自定義注解:自己定義的注解,通過關鍵字@interface實作。接口名即為注解名,接口中的方法即為注解中可加的屬性。
例:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Entity {
public String value() default "";
}
@Entity("student")
public class Student {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
總結,初步了解了Ioc的原理及使用和spring的一些功能,為後面的源碼學習打基礎,一步步掌握spring。