Spring系列之註解配置
Spring是輕程式碼而重配置的框架,配置比較繁重,影響開發效率,所以註解開發是一種趨勢,註解代替xml配置檔案可以簡化配置,提高開發效率
你本來要寫一段很長的程式碼來構造一個Beam物件,但是如果使用註解的話只要使用一個註解符號即可
下面我們來講講一些經常使用的註解符號
@Component 使用類上用於例項化Bean
@Controller 使用web層類上用於例項化Bean
@Service 使用在Service層類上用於例項化service
@Repository 使用在dao層類上用於例項化Bean
@Autorwired 使用在欄位上用於根據型別依賴注入
@Qualifier 結合結合@Autowired一起使用根據名稱進行依賴注入
@Resource 相當於@Autowired+@Qualifier一起使用
@Scope 標註bean的範圍
@PostConstruct 使用該在方法上標註該方法是Bean的初始化方法
@PostDestory 使用在方法上標註該方法是Bean的銷燬方法
這三個沒有什麼區別,不過是為了在後期讀程式碼的時候更加利於我們區分,比如看到@Controller就知道這是web層,看到@Service就知道這是service層
@Component 使用類上用於例項化Bean
@Controller 使用web層類上用於例項化Bean
@Service 使用在Service層類上用於例項化service
@Repository 使用在dao層類上用於例項化Bean
所以我們只需講一個即可,其他的使用方法均相同,這裡我們使用@Component來講解
定義一個userDaolmp類
package com.pjh.dao;
import com.pjh.dao.Imp.userdao;
import org.springframework.stereotype.Component;
@Component("userDaoImp")
public class userDaoImp implements userdao {
public void save() {
System.out.println("save");
}
}
定義一個測試類測試
@Test
public void test(){
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
userdao userDaoImp =(userdao) classPathXmlApplicationContext.getBean("userDaoImp");
userDaoImp.save();
}
然後我們就發現瞭如下報錯
由藍色的劃線部分我們可以看出問題是:沒有一個名叫userDaoImp的bean
這是為什呢?因為我們雖然寫了註解,但是我們要讓applicationContext.xml知道我們使用了註解,要告訴他哪裡有個bean。所以我們在applicationContext中還需要加入以下配置
名稱空間:xmlns:context="http://www.springframework.org/schema/context
約束路徑:http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
註解的元件掃描:
<context:component-scan base-package="com.pjh"/>
成功執行
接下來我們再來講講如何使用註解進行注入
方式一:使用@Autowired+@Qualifier
目的:建立一個userdao類將其注入帶service類中
userdao類程式碼
package com.pjh.dao;
import com.pjh.dao.Imp.userdao;
import org.springframework.stereotype.Component;
@Component("userDaoImp")
public class userDaoImp implements userdao {
public void save() {
System.out.println("save");
}
}
service類程式碼
package com.pjh.service.Imp;
import com.pjh.dao.Imp.userdao;
import com.pjh.dao.userDaoImp;
import com.pjh.service.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import javax.xml.bind.SchemaOutputResolver;
@Repository("serviceImp")
public class serviceImp implements service {
@Autowired
@Qualifier("userDaoImp")
private userDaoImp userDaoImp;
public void save() {
System.out.println("sssssss");
userDaoImp.save();
}
}
測試類
@Test
public void test(){
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
service service =(service) classPathXmlApplicationContext.getBean("serviceImp");
service.save();
}
結果
方式二:使用@Resource()
就是把 @Autowired + @Qualifier("userDaoImp")換成@Resource(name="userDaoImp"),其餘程式碼均與方式一相同
package com.pjh.service.Imp;
import com.pjh.dao.Imp.userdao;
import com.pjh.dao.userDaoImp;
import com.pjh.service.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import javax.xml.bind.SchemaOutputResolver;
@Repository("serviceImp")
public class serviceImp implements service {
/* @Autowired
@Qualifier("userDaoImp")*/
@Resource(name="userDaoImp")
private userDaoImp userDaoImp;
public void save() {
System.out.println("sssssss");
userDaoImp.save();
}
}
結果
令人蛋碎的事情來了,報錯了,意思是不支援版本5
解決方案:
File->setting下設定專案的jdk版本
File->ProjectStruct下設定版本
結果
又報錯了,這。。。。。我tm心態崩了呀
根據報錯的內容是報了個空指標異常,這是為什麼呢?為什麼使用@Autowired + @Qualifier("userDaoImp")不報錯換成@Resource(name="userDaoImp")就報空指標呢
原因:jdk版本不支援
解決方案:
1.更換本地的jdk版本,最好jdk1.8以上,jdk9不支援有bug
2.再maven.pom檔案中引入如下依賴
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-annotations-api</artifactId>
<version>7.0.47</version>
</dependency>
結果
成功執行
終於解決完了
使用@Scope註解標註Bean的範圍
使用@Scope("prototype")
package com.pjh.dao;
import com.pjh.dao.Imp.userdao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component("userDaoImp")
@Scope("prototype")
public class userDaoImp implements userdao {
public void save() {
System.out.println("save");
}
}
測試程式碼
@Test
public void test(){
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
userdao userdao =(userdao) classPathXmlApplicationContext.getBean("userDaoImp");
userdao userdao1 =(userdao) classPathXmlApplicationContext.getBean("userDaoImp");
System.out.println(userdao);
System.out.println(userdao1);
}
結果
使用@Scope("singleton")
package com.pjh.dao;
import com.pjh.dao.Imp.userdao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component("userDaoImp")
@Scope("singleton")
public class userDaoImp implements userdao {
public void save() {
System.out.println("save");
}
}
結果
在這裡順便給大家複習複習singleton與prototype的區別吧
singleton
Bean的例項化個數:1個
Bean的例項化時機:當Spring核心配置檔案被載入時
Bean的生命週期:
物件建立:當應用載入時物件建立
物件執行:只要容器在,物件就一直活著
物件銷燬:當應用解除安裝,容器銷燬時
prototype:在使用getBean方法的時候建立bean
prototype
Bean的例項化格式:多個
Bean的例項化時機:當呼叫getBean()方法時,例項化Bean
物件建立:當使用物件時,建立新的物件例項
物件執行:只要物件在使用中,物件就一直存在
物件銷燬:物件長時間不使用,就會被java的垃圾回收機制回收
初始化方法和銷燬方法
初始化方法
@PostConstract
@PostConstruct
public void constract(){
System.out.println("初始化方法");
}
銷燬方法
@PostDestroy
@PreDestroy
public void destroy(){
System.out.println("在物件銷燬前執行");
}
@Value()進行注入
package com.pjh.dao;
import com.pjh.dao.Imp.userdao;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component("userDaoImp")
@Scope("singleton")
public class userDaoImp implements userdao {
public void save() {
System.out.println("save");
System.out.println("讀取配置檔案:"+one);
System.out.println("普通型別:"+a);
}
@Value("${one.one}")
private String one;
@Value("4")
private String a;
}
配置檔案資訊
one.one=1
applicationContext中新增的內容
<context:property-placeholder location="classpath*:one.properties"/>
測試程式碼
@Test
public void test(){
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
userdao userdao =(userdao) classPathXmlApplicationContext.getBean("userDaoImp");
userdao.save();
}
結果
使用上面的註解還不可以全部替代xml配置檔案,還需要使用註解替代的配置如下
非自定義的Bean的配置:
載入properties檔案的配置:<context:property-placeholder>
註解掃描的配置:context:component-scan
引入其他檔案:
Spring新註解
@Configuration 用於指定當前類是一個Spring配置類,建立容器時會從該類上載入註解,該類不能是匿名類與final類
@ComponentScan 用於指定Spring在初始化容器的時候要掃描包
作用與Spring中的此程式碼相同:context:component-scan
@Bean 使用方法,將該方法的返回值返回到容器中
@Import 用於匯入其他配置類
@PropertySource 用於載入properties檔案中的配置
案例
核心配置類
package com.pjh.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
/*標誌該類是核心配置類*/
@Configuration
/*掃描包*/
@Component("com/pjh")
/*匯入其他配置類*/
@Import(DataSourceConfig.class)
public class Springconfig {
}
副配置類
package com.pjh.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
/*載入配置檔案*/
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/*Spring會將當前方法的返回值以指定名稱儲存到Spring容器中*/
@Bean("dataSource")
public DataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(username);
dataSource.setPassword(password);
return dataSource;
}
}
測試函式
@Test
public void test() throws SQLException {
ApplicationContext applicationContext = new
AnnotationConfigApplicationContext(Springconfig.class);
DataSource bean = (DataSource)applicationContext.getBean("dataSource");
Connection connection = bean.getConnection();
System.out.println(connection);
}
結果
成功建立connection連線
Spring整合junit
為什麼使用Spring整合junit?
在測試類中每個類都要寫下面的兩行程式碼
ApplicationContext applicationContext = new
AnnotationConfigApplicationContext(Springconfig.class);
DataSource bean = (DataSource)applicationContext.getBean("dataSource");
這兩行程式碼的作用是獲取容器,不寫的話報空指標異常
為了讓我們測試的時候不用進行反覆的寫上述兩行的操作,我們使用Spring來整合junit,用springjunit來建立spring容器,
我們只需將配置檔案的名稱告訴他們即可,將需要的bean直接在容器中進行注入
Spring整合junit的步驟
需要匯入的jar包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>