Java自學之路-Java中級教程-9:Spring自動掃描注入component-scan以及@Service註解
Spring的@Autowired註解可以實現自動裝配,即不需要在xml中再顯式地注入依賴。
前面幾節的資料庫訪問類PersonDataAccessObject實際上已有dataSource和jdbcTemplate兩種實現,為了能夠繼續使用兩種方式,可以給PersonDataAccessObject定義一個介面,名為PersonDao,然後把dataSource和jdbcTemplate兩種實現分別定義兩個實現介面的類PersonDataSourceDaoImpl及PersonJdbcTemplateDaoImpl。
package com.helloworld.dao; import java.util.List; import com.helloworld.Person; public interface PersonDao { public List getPersonList(); }
package com.helloworld.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import javax.sql.DataSource; import com.helloworld.Person; public class PersonDataSourceDaoImpl implements PersonDao { private DataSource dataSource; public DataSource getDataSource() { return dataSource; } public List getPersonList() throws Exception { Connection conn = dataSource.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("select * from new_table"); List personList = new ArrayList(); while (rs.next()) { Person person = new Person(); person.setId(rs.getInt(1)); person.setNation(rs.getString(2)); personList.add(person); } if (rs != null) { rs.close(); } if (stmt != null) { stmt.close(); } if (conn != null) { conn.close(); } return personList; } public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } }
package com.helloworld.dao; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.springframework.jdbc.core.JdbcTemplate; import com.helloworld.Person; public class PersonJdbcTemplateDaoImpl implements PersonDao { private JdbcTemplate jdbcTemplate; public JdbcTemplate getJdbcTemplate() { return jdbcTemplate; } public List getPersonList() throws Exception { List rowList = jdbcTemplate.queryForList("select * from new_table"); List personList = new ArrayList(); Iterator it = rowList.iterator(); while (it.hasNext()) { Person person = new Person(); Map personrMap = (Map) it.next(); person.setId((Integer) personrMap.get("id")); person.setNation((String) personrMap.get("nation")); personList.add(person); } return personList; } public void setJdbcTemplate(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } }
在applicationContext-dao.xml檔案中,可以注入兩個不同的Dao實現personJdbcTemplateDao和personDataSourceDao。
在SpringContextMain的main()方法中,無論獲取哪一個實現,都可以強轉為PersonDao,用介面的方式來呼叫查詢列表方法personDao.getPersonList()。
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("com/helloworld/dao/applicationContext-dao.xml");
PersonDao personDao = (PersonDao) ac.getBeanFactory().getBean("personJdbcTemplateDao");
List personList = personDao.getPersonList();
personDao = (PersonDao) ac.getBeanFactory().getBean("personDataSourceDao");
List personList2 = personDao.getPersonList();
無論是注入DataSource還是JdbcTemplate,都要生成setter和getter方法。這是因為Spring就是通過setter和getter方法來注入依賴的例項和得到注入的例項。
public JdbcTemplate getJdbcTemplate() {
return jdbcTemplate;
}
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
這裡的Dao即是資料訪問物件(Data Access Object),Person即是資料模型物件(Model)。在Web程式設計中有一個MVC模式的概念,其中的M即是這裡的Model。MVC模式講究分層次設計,把應用程式大致分為Model層、View層、Controller層,即資料模型層、表現層、控制層。
從分層的角度來說,Dao資料訪問層一般不直接給外界使用,而是在中間封裝一層Service業務層,由Service呼叫資料訪問層的實現,並在Service中用資料訪問層得到的資料模型來再處理一些複雜的業務。
新建一個類PersonService,所在包名為com.helloworld.service。在PersonService新建helpToDo(),並注入PersonDao的依賴。
package com.helloworld.service;
import java.util.List;
import com.helloworld.Hand;
import com.helloworld.Person;
import com.helloworld.dao.PersonDao;
public class PersonService {
private PersonDao personDao;
public PersonDao getPersonDao() {
return personDao;
}
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
public List helpToDo() throws Exception {
List personList = personDao.getPersonList();
for (Person person : personList) {
Hand hand = person.getHand();
// 讓每個Person幫手做一些事...
if (hand != null) {
System.out.println(hand.toString());
} else {
System.out.println("No hand!");
}
}
return personList;
}
}
這樣,Service可以使用Dao取到的資料進行一些業務處理。至於使用Dao的哪個實現,可以在xml中進行注入,比如注入bean id="personService" class="com.helloworld.dao.PersonService",再注入屬性property name="personDao" ref="personJdbcTemplateDao"。
在SpringContextMain可以改用獲取PersonService的物件例項,並呼叫方法personService.helpToDo()來處理業務上的事。
PersonService personService = (PersonService) ac.getBeanFactory().getBean("personService");
personService.helpToDo();
如果只想保留com.helloworld.dao.PersonJdbcTemplateDaoImpl的實現,還可以直接注入一個bean id="personDao" class="com.helloworld.dao.PersonJdbcTemplateDaoImpl",直接讓Service拿到這個實現來用。
這樣只保留了Dao的一種實現,也就是Service中依賴的就是com.helloworld.dao.PersonJdbcTemplateDaoImpl。
前面使用了@Autowired和@Component註解,可以省略在xml中注入這些bean,所以完全可以使用註解來給Service注入Dao。
在applicationContext-dao.xml中加入context的宣告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.helloworld"的標籤,意思是在com.helloworld包中掃描@Component的類來生成註解的例項。在需要註解的類上,加上相應的註解@Component和@Autowired,而在PersonService類上加入@Service註解,表明這是一個Service。
@Component
public class PersonJdbcTemplateDaoImpl implements PersonDao {
@Autowired
private JdbcTemplate jdbcTemplate;
}
@Service
public class PersonService {
@Autowired
private PersonDao personDao;
}
如此一來,xml中只有jdbcTemplate和dataSource的配置了,配置簡潔了許多。
配套進階視訊教程:
Java視訊教程