java调用外联服务用xml,Spring IOC 依赖注入的两种方式:XML和注解
IoC,直觀地講,就是容器控制程序之間的關系,而非傳統實現中,由程序代碼直接操控。這也就是所謂“控制反轉”的概念所在。控制權由應用代碼中轉到了外部容器,控制權的轉移是所謂反轉。IoC還有另外一個名字——“依賴注入(Dependency Injection)”。從名字上理解,所謂依賴注入,即組件之間的依賴關系由容器在運行期決定,形象地說,即由容器動態地將某種依賴關系注入到組件之中。
依賴注入的原理
依賴注入的方式---XML配置
依賴注入的方式---注解的方式
Spring 它的核心就是IOC和AOP。而IOC中實現Bean注入的實現方式之一就是DI(依賴注入)。
一 DI的原理
DI的基本原理:對象之間的依賴關系只會通過三種方式:構造函數參數,工廠方法的參數以及構造函數或工廠方法創建的對象屬性設置。因此,容器的工作哦就是在創建Bean時注入所有的依賴關系。相對于由Bean自己控制其實例化,直接在構造器中指定依賴關系或者類似服務定位器(Service Locator)這三種自主控制依賴關系注入的方法,而控制權從根本上發生改變,即控制反轉(Inverse of Controll)---IOC.
應用DI規則后,我們不用在關注對象之間的依賴關系,從而達到高層次的松耦合。DI有兩種實現方式---Setter/getter方式(傳值方式)和構造器方式(引用方式)。
下面通過一個生動形象的例子介紹控制反轉。
比如,一個女孩希望找到合適的男朋友,如圖6-2所示,可以有3種方式,即青梅竹馬、親友介紹、父母包辦。
第1種方式是青梅竹馬,如圖6-3所示。
通過代碼表示如下。
public class Girl {
void kiss(){
Boy boy = new Boy();
}
}
第2種方式是親友介紹,如圖6-4所示。
通過代碼表示如下。
public class Girl {
void kiss(){
Boy boy = BoyFactory.createBoy();
}
}
第3種方式是父母包辦,如圖6-5所示。
通過代碼表示如下。
public class Girl {
void kiss(Boy boy){
// kiss boy
boy.kiss();
}
}
哪一種為控制反轉IoC呢?雖然在現實生活中我們都希望青梅竹馬,但在Spring世界里,選擇的卻是父母包辦,它就是控制反轉,而這里具有控制力的父母,就是Spring所謂的容器概念。
典型的IoC可以如圖6-6所示。
二、DI的方式---XML配置
第1種是通過接口注射,這種方式要求我們的類必須實現容器給定的一個接口,然后容器會利用這個接口給我們這個類注射它所依賴的類。Setter/getter方法
這種方式也是Spring推薦的方式
1)、beans.xml (外部注入的方式)
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.or...
http://www.springframework.or... http://www.springframework.org/schema/context/spring-context-2.5.xsd">
2) PersonDao.java
package com.spring.dao;
public interface PersonDao {
public void add();
}
3) PersonDaoImpl.java
package com.spring.dao.impl;
import com.spring.dao.PersonDao;
public class PersonDaoImpl implements PersonDao {
public void add() {
System.out.println("PersonDao.add() is running.");
}
}
4) PersonService.java
package com.spring.service;
public interface PersonService {
public? void save();
}
5) PersonServiceBean.java
package com.spring.service.impl;
import com.spring.dao.*;
import com.spring.service.PersonService;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class PersonServiceBean implements PersonService {
private PersonDao personDao;
public PersonServiceBean(){
System.out.println("personServiceBean.constructor() is running.");
}
public PersonDao getPersonDao() {
return personDao;
}
public void setPersonDao(PersonDao personDao) {
this.personDao = personDao;
}
public void save(){
System.out.println("Name:" );
personDao.add();
}
@PostConstruct
public void init(){
System.out.println("PersonServiceBean.init() is running.");
}
@PreDestroy
public void destory(){
System.out.println("PersonServiceBean.destory() is running.");
}
}
6) SpringIOCTest.java(測試類)
package junit.test;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.service.PersonService;
public class SpringIOCTest {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test public void instanceSpring(){
AbstractApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
PersonService personService = (PersonService)context.getBean("personService");
personService.save();
//????????? context.close();
}
}
我們還可以采用內部注入的方式來處理:
Beans.xml修改如下:
2、構造器注入
這種方式Spring同樣給予了實現,它和通過setter方式一樣,都在類里無任何侵入性,但是,不是沒有侵入性,只是把侵入性轉移了,顯然第1種方式要求實現特定的接口,侵入性非常強,不方便以后移植
2) PersonService.java:同Setter方法注入
3) PersonServiceBean.java
public class PersonServiceBean implements PersonService {
private PersonDao personDao;
private String name;
public PersonServiceBean(){
System.out.println("personServiceBean.constructor() is running.");
}
public PersonServiceBean(PersonDao personDao, String name) {
this.personDao = personDao;
this.name = name;
}
//????? public PersonDao getPersonDao() {
//????????? return personDao;
//????? }
//???? public void setPersonDao(PersonDao personDao) {
//???????? this.personDao = personDao;
//????? }
public void save(){
System.out.println("Name:"+name );
personDao.add();
}
@PostConstruct
public void init(){
System.out.println("PersonServiceBean.init() is running.");
}
@PreDestroy
public void destory(){
System.out.println("PersonServiceBean.destory() is running.");
}
}
4) PersonDao.java:同Setter方法注入
5) PersonDaoImpl.java:同Setter方法注入
6) 測試類(SpringIOCTest.java):同上
控制臺信息
PersonServiceBean.init() is running.
Name:Jamson
PersonDao.add() is running.
PersonServiceBean.destory() is running.
三 DI的方式---注解的配置
自從Jdk5中引入Annotation類后,在EJB和Spring中得到廣泛的使用,也越來越被開發者們在平時的應用中使用。主要是用在Field上的注入。在日常的應用開發中,一個項目中有很多的bean,如果使用XML文件配置,就會導致配置文件難以管理。使用注解注入的時候,能夠使bean的配置文件內容不至于繁雜。
1、古老的注入方式:
實現類:
Java代碼 /**
@title UserServiceImpl.java
@description UserService實現類
@author cao_xhu
@version
@create_date Oct 30, 2009
@copyright (c) CVIC SE
*/
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
...
}
配置文件:
Xml代碼
class="springlive.service.impl.UserServiceImpl">
2、使用注解的方式:
2.1、Autowired注解
<1>對成員變量注解
實現類:
Java代碼 @Autowired
private IndustryDao industryDao;
...
<2>set方法注解
Java代碼 @Autowired
public void setDao(IndustryDao industryDao)
{
super.setDao(industryDao);
}
配置文件:
Xml代碼
class="efs.sadapter.system.industry.dao.hibernate.HibernateIndustryDao" />
class="efs.sadapter.system.industry.service.impl.IndustryServiceImpl" />
@Autowired可以對成員變量、方法和構造函數進行標注,來完成自動注入。
@Autowired的標注位置不同,它們都會在Spring在初始化industryService這個bean時,自動裝配industryDao這個屬性,區別是:第一種實現中,Spring會直接將IndustryDao類型的唯一一個bean賦值給industryDao這個成員變量;第二種實現中,Spring會調用setDao方法來將IndustryDao類型的唯一一個bean裝配到industryDao這個屬性。
2.2、@Qualifier
@Autowired是根據類型進行自動注入的,如果spring配置文件中存在多個IndustryDao類型的bean時,或者不存在IndustryDao類型的bean,都會拋出異常。
存在多個類型的實例時,按id注入@Qualifier("core.system.hibernateService")
Java代碼 HibernateService hibernateService;
@Autowired
public void setHibernateService(@Qualifier("core.system.hibernateService")
HibernateService hibernateService)
{
this.hibernateService = hibernateService;
}
若不存在某類型的實例:告訴 Spring:在找不到匹配 Bean 時也不報錯
Java代碼 @Autowired(required = false)
public void setHibernateService(@Qualifier("core.system.hibernateService")
HibernateService hibernateService)
{
this.hibernateService = hibernateService;
}
2.3、使用 JSR-250 的注解
<1> @Resource
spring支持@Resource、@PostConstruct以及@PreDestroyJSR-250的標準注解。
@Resource可以按type注入,也可以按name注入。@Resource默認按byName自動注入。
Spring將@Resource注解的name屬性解析為bean的名字,而type屬性則解析為bean的類型。所以如果使用name屬性,則使用byName的自動注入策略,而使用type屬性時則使用byType自動注入策略。如果既不指定name也不指定type屬性,這時將通過反射機制使用byName自動注入策略。
@Resource裝配順序
如果同時指定了name和type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則拋出異常
如果指定了name,則從上下文中查找名稱(id)匹配的bean進行裝配,找不到則拋出異常
如果指定了type,則從上下文中找到類型匹配的唯一bean進行裝配,找不到或者找到多個,都會拋出異常
如果既沒有指定name,又沒有指定type,則自動按照byName方式進行裝配(見2);如果沒有匹配,則回退為一個原始類型(UserDao)進行匹配,如果匹配則自動裝配;
<2> @PostConstruct 和 @PreDestroy
Spring 容器中的 Bean 是有生命周期的,Spring 允許在 Bean 在初始化完成后以及 Bean 銷毀前執行特定的操作,您既可以通過實現 InitializingBean/DisposableBean 接口來定制初始化之后 / 銷毀之前的操作方法,也可以通過 元素的 init-method/destroy-method 屬性指定初始化之后 / 銷毀之前調用的操作方法。
JSR-250 為初始化之后/銷毀之前方法的指定定義了兩個注釋類,分別是 @PostConstruct 和 @PreDestroy,這兩個注釋只能應用于方法上。標注了 @PostConstruct 注釋的方法將在類實例化后調用,而標注了 @PreDestroy 的方法將在類銷毀之前調用。
使用 @PostConstruct 和 @PreDestroy 注釋的 Boss.java
Java代碼 package com.baobaotao;
import javax.annotation.Resource;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class Boss {
@Resource
private Car car;
@Resource(name = "office")
private Office office;
@PostConstruct
public void postConstruct1(){
System.out.println("postConstruct1");
}
@PreDestroy
public void preDestroy1(){
System.out.println("preDestroy1");
}
…
}
測試類代碼:
Java代碼 package com.baobaotao;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AnnoIoCTest {
public static void main(String[] args) {
String[] locations = {"beans.xml"};
ClassPathXmlApplicationContext ctx =
new ClassPathXmlApplicationContext(locations);
Boss boss = (Boss) ctx.getBean("boss");
System.out.println(boss);
ctx.destroy();// 關閉 Spring 容器,以觸發 Bean 銷毀方法的執行
}
}
標注了 @PostConstruct 的 postConstruct1() 方法將在 Spring 容器啟動時,創建 Boss Bean 的時候被觸發執行,而標注了 @PreDestroy 注釋的 preDestroy1() 方法將在 Spring 容器關閉前銷毀 Boss Bean 的時候被觸發執行。
3、使用 @Component
雖然我們可以通過 @Autowired 或 @Resource 在 Bean 類中使用自動注入功能,但是 Bean 還是在 XML 文件中通過 進行定義 —— 也就是說,在 XML 配置文件中定義 Bean,通過 @Autowired 或 @Resource 為 Bean 的成員變量、方法入參或構造函數入參提供自動注入的功能。能否也通過注釋定義 Bean,從 XML 配置文件中完全移除 Bean 定義的配置呢?答案是肯定的,我們通過 Spring 2.5 提供的 @Component 注釋就可以達到這個目標了。
下面,我們完全使用注釋定義 Bean 并完成 Bean 之間裝配:
使用 @Component 注釋的Woman.java
Java代碼 @Component
public class Woman{
…
}
使用 @Component 注釋的Woman.java
Java代碼 @Component
public class Man{
…
}
這樣,我們就可以在 Human類中通過 @Autowired 注入前面定義的 Woman和 Man Bean 了。
Java代碼 @Component("human")
public class Human{
@Autowired
private Woman woman;
@Autowired
private Man man;
…
}
一般情況下,Bean 都是 singleton 的,需要注入 Bean 的地方僅需要通過 byType 策略就可以自動注入了,所以大可不必指定 Bean 的名稱。如果需要使用其它作用范圍的 Bean,可以通過 @Scope 注釋來達到目標:
Java代碼 @Scope("prototype")
@Component("human")
public class Human{
…
}
在使用 @Component 注釋后,Spring 容器必須啟用類掃描機制以啟用注釋驅動 Bean 定義和注釋驅動 Bean 自動注入的策略。Spring 2.5 對 context 命名空間進行了擴展,提供了這一功能,請看下面的配置:
Xml代碼 <?xml version="1.0" encoding="UTF-8" ?>
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
參考資料:
總結
以上是生活随笔為你收集整理的java调用外联服务用xml,Spring IOC 依赖注入的两种方式:XML和注解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 装中央空调要多少钱啊?
- 下一篇: netcore 内存限制_.NET Co