1. 程式人生 > >7、SSM框架-Spring之IOC的註解注入(7)

7、SSM框架-Spring之IOC的註解注入(7)

用註解來向Spring容器註冊Bean。需要在applicationContext.xml中註冊<context:component-scan base-package=”pagkage1[,pagkage2,…,pagkageN]”/>。
如:在base-package指明一個包
 <context:component-scan base-package="cn.gacl.java"/>
表明cn.gacl.java包及其子包中,如果某個類的頭上帶有特定的註解【@Component/@Repository/@Service/@Controller】,就會將這個物件作為Bean註冊進Spring容器。也可以在<context:component-scan base-package=” ”/>中指定多個包,如:
 <context:component-scan base-package="cn.gacl.dao.impl,cn.gacl.service.impl,cn.gacl.action"/>
多個包逗號隔開。

以下為常用的四個註解,關於其他的註解,我會在後面的時候進行總結和整理,此處對以下四個有個大體的瞭解即可

一、基於@Component註解的配置

spring 2.5 中除了提供 @Component 註釋外,還定義了幾個擁有特殊語義的註釋,它們分別是:@Repository、@Service 和 @Controller。
在目前的 Spring 版本中,這 3 個註釋和 @Component 是等效的,但是從註釋類的命名上,很容易看出這 3 個註釋分別和持久層、業務層和控制層(Web 層)相對應。
雖然目前這3 個註釋和 @Component 相比沒有什麼新意,但 Spring 將在以後的版本中為它們新增特殊的功能。所以,如果 Web 應用程式採用了經典的三層分層結構的話,最好在持久層、業務層和控制層分別採用上述註解對分層中的類進行註釋。

1、@controller 控制器(注入服務)

2、@service 服務(注入dao)

3、@repository dao(實現dao訪問)

4、@component (把普通pojo例項化到spring容器中,相當於配置檔案中的<bean id="" class=""/>)


@component用法如下:

print?在CODE上檢視程式碼片派生到我的程式碼片
  1. @Component("userDao")  
  2. public class UserDaoImp implements UserDao{  
  3.     @Override  
  4.     public void add(User user) {  
  5.         System.out.println(user.getName());    
  6.         System.out.println(user.getSex());   
  7.         System.out.println(user.getAge());   
  8.     }  
  9. }  
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. @Component("userDao")  
  2. public class UserDaoImp implements UserDao{  
  3.     @Override  
  4.     public void add(User user) {  
  5.         System.out.println(user.getName());    
  6.         System.out.println(user.getSex());   
  7.         System.out.println(user.getAge());   
  8.     }  
  9. }  
@Component("userDao")
public class UserDaoImp implements UserDao{

	@Override
	public void add(User user) {
		System.out.println(user.getName());  
        System.out.println(user.getSex()); 
        System.out.println(user.getAge()); 
	}

}

  在類上使用@Component註解,表示該類定義為Spring管理Bean,使用預設value(可選)屬性表示Bean識別符號。

相當於:

print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <bean id="userDao" class="com.mucfc.dao.UserDao"/>  
[html] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <bean id="userDao" class="com.mucfc.dao.UserDao"/>  
         <bean id="userDao" class="com.mucfc.dao.UserDao"/>
@Component,@Service,@Controller,@Repository註解的類,並把這些類納入進spring容器中管理。
下面寫這個是引入component的掃描元件
print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <!-- 配置的bean所在包的位置 -->    
  2. lt;context:component-scan base-package="com.mucfc" />  
[html] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <!-- 配置的bean所在包的位置 -->    
  2. lt;context:component-scan base-package="com.mucfc" />  
	 <!-- 配置的bean所在包的位置 -->  
	<context:component-scan base-package="com.mucfc" />
其中base-package為需要掃描的包(含所有子包)

@Component泛指元件,當元件不好歸類的時候,我們可以使用這個註解進行標註。

二、使用例項

User.Java:用@Repository註解

print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.mucfc.model;  
  2. import org.springframework.context.annotation.Scope;  
  3. import org.springframework.stereotype.Repository;  
  4. @Repository("user")  
  5. @Scope("prototype")  
  6. //@Repository用於標註資料訪問元件,即DAO元件  
  7. //@Scope("prototype")讓其每次返回不同的例項,預設是單例  
  8. public class User {  
  9.     private String name;  
  10.     private String sex;  
  11.     public String getName() {  
  12.         return name;  
  13.     }  
  14.     public void setName(String name) {  
  15.         this.name = name;  
  16.     }  
  17.     public String getSex() {  
  18.         return sex;  
  19.     }  
  20.     public void setSex(String sex) {  
  21.         this.sex = sex;  
  22.     }  
  23.     public int getAge() {  
  24.         return age;  
  25.     }  
  26.     public void setAge(int age) {  
  27.         this.age = age;  
  28.     }  
  29.     private int age;  
  30. }  
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.mucfc.model;  
  2. import org.springframework.context.annotation.Scope;  
  3. import org.springframework.stereotype.Repository;  
  4. @Repository("user")  
  5. @Scope("prototype")  
  6. //@Repository用於標註資料訪問元件,即DAO元件  
  7. //@Scope("prototype")讓其每次返回不同的例項,預設是單例  
  8. public class User {  
  9.     private String name;  
  10.     private String sex;  
  11.     public String getName() {  
  12.         return name;  
  13.     }  
  14.     public void setName(String name) {  
  15.         this.name = name;  
  16.     }  
  17.     public String getSex() {  
  18.         return sex;  
  19.     }  
  20.     public void setSex(String sex) {  
  21.         this.sex = sex;  
  22.     }  
  23.     public int getAge() {  
  24.         return age;  
  25.     }  
  26.     public void setAge(int age) {  
  27.         this.age = age;  
  28.     }  
  29.     private int age;  
  30. }  
package com.mucfc.model;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

@Repository("user")
@Scope("prototype")
//@Repository用於標註資料訪問元件,即DAO元件
//@Scope("prototype")讓其每次返回不同的例項,預設是單例
public class User {
	private String name;
	private String sex;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	private int age;
	

}
UserDao.java
print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.mucfc.dao;  
  2. import com.mucfc.model.User;  
  3. public interface UserDao {  
  4.     public void add(User user);  
  5. }  
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.mucfc.dao;  
  2. import com.mucfc.model.User;  
  3. public interface UserDao {  
  4.     public void add(User user);  
  5. }  
package com.mucfc.dao;

import com.mucfc.model.User;

public interface UserDao {
	public void add(User user);
}
UserDaoImp.java:用@Controller註解
print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.mucfc.daoimp;  
  2. import org.springframework.stereotype.Controller;  
  3. import com.mucfc.dao.UserDao;  
  4. import com.mucfc.model.User;  
  5. @Controller("userDao")  
  6. //@Controller用於標註控制層元件  
  7. public class UserDaoImp implements UserDao{  
  8.     @Override  
  9.     public void add(User user) {  
  10.         System.out.println(user.getName());    
  11.         System.out.println(user.getSex());   
  12.         System.out.println(user.getAge());   
  13.     }  
  14. }  
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.mucfc.daoimp;  
  2. import org.springframework.stereotype.Controller;  
  3. import com.mucfc.dao.UserDao;  
  4. import com.mucfc.model.User;  
  5. @Controller("userDao")  
  6. //@Controller用於標註控制層元件  
  7. public class UserDaoImp implements UserDao{  
  8.     @Override  
  9.     public void add(User user) {  
  10.         System.out.println(user.getName());    
  11.         System.out.println(user.getSex());   
  12.         System.out.println(user.getAge());   
  13.     }  
  14. }  
package com.mucfc.daoimp;

import org.springframework.stereotype.Controller;

import com.mucfc.dao.UserDao;
import com.mucfc.model.User;

@Controller("userDao")
//@Controller用於標註控制層元件
public class UserDaoImp implements UserDao{

	@Override
	public void add(User user) {
		System.out.println(user.getName());  
        System.out.println(user.getSex()); 
        System.out.println(user.getAge()); 
	}

}

@Controller對應表現層的Bean,也就是Action,例如:

1 @Controller
2 @Scope("prototype")
3 public class UserAction extends BaseAction<User>{
4 ……
5 }

使用@Controller註解標識UserAction之後,就表示要把UserAction交給Spring容器管理,在Spring容器中會存在一個名字為"userAction"的action,這個名字是根據UserAction類名來取的。注意:如果@Controller不指定其value【@Controller】,則預設的bean名字為這個類的類名首字母小寫,如果指定value【@Controller(value="UserAction")】或者【@Controller("UserAction")】,則使用value作為bean的名字

這裡的UserAction還使用了@Scope註解,@Scope("prototype")表示將Action的範圍宣告為原型,可以利用容器的scope="prototype"來保證每一個請求有一個單獨的Action來處理,避免struts中Action的執行緒安全問題。spring 預設scope 是單例模式(scope="singleton"),這樣只會建立一個Action物件,每次訪問都是同一Action物件,資料不安全,struts2 是要求每次次訪問都對應不同的Action,scope="prototype" 可以保證當有請求的時候都建立一個Action物件

UserService.java:用@Service註解
print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.mucfc.service;  
  2. import javax.annotation.Resource;  
  3. import org.springframework.stereotype.Service;  
  4. import com.mucfc.dao.UserDao;  
  5. import com.mucfc.model.User;  
  6. @Service("userService")  
  7. //@Service用於標註業務層元件  
  8. public class UserService {  
  9.      //setter注入介面、面向介面程式設計    
  10.     private UserDao userdao ;    
  11.     public void add(User user){    
  12.         userdao.add(user) ;    
  13.     }    
  14.     public UserDao getUserdao() {    
  15.         return userdao;    
  16.     }    
  17.     //註解    
  18.     @Resource(name="userDao")    
  19.     public void setUserdao(UserDao userdao) {    
  20.         this.userdao = userdao;    
  21.     }    
  22. }  
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.mucfc.service;  
  2. import javax.annotation.Resource;  
  3. import org.springframework.stereotype.Service;  
  4. import com.mucfc.dao.UserDao;  
  5. import com.mucfc.model.User;  
  6. @Service("userService")  
  7. //@Service用於標註業務層元件  
  8. public class UserService {  
  9.      //setter注入介面、面向介面程式設計    
  10.     private UserDao userdao ;    
  11.     public void add(User user){    
  12.         userdao.add(user) ;    
  13.     }    
  14.     public UserDao getUserdao() {    
  15.         return userdao;    
  16.     }    
  17.     //註解    
  18.     @Resource(name="userDao")    
  19.     public void setUserdao(UserDao userdao) {    
  20.         this.userdao = userdao;    
  21.     }    
  22. }  
package com.mucfc.service;
import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import com.mucfc.dao.UserDao;
import com.mucfc.model.User;

@Service("userService")
//@Service用於標註業務層元件
public class UserService {
	 //setter注入介面、面向介面程式設計  
    private UserDao userdao ;  
    public void add(User user){  
        userdao.add(user) ;  
    }  
    public UserDao getUserdao() {  
        return userdao;  
    }  
    //註解  
    @Resource(name="userDao")  
    public void setUserdao(UserDao userdao) {  
        this.userdao = userdao;  
    }  
}
注意:在Action宣告的“userService”變數的型別必須是“UserServiceImpl”或者是其父類“UserService”,否則由於型別不一致而無法注入,由於Action中的宣告的“userService”變數使用了@Resource註解去標註,並且指明瞭其name = "userService",這就等於告訴Spring,說我Action要例項化一個“userService”,你Spring快點幫我例項化好,然後給我,當Spring看到userService變數上的@Resource的註解時,根據其指明的name屬性可以知道,Action中需要用到一個UserServiceImpl的例項,此時Spring就會把自己建立好的名字叫做"userService"的UserServiceImpl的例項注入給Action中的“userService”變數,幫助Action完成userService的例項化,這樣在Action中就不用通過“UserService userService = new UserServiceImpl();”這種最原始的方式去例項化userService了。如果沒有Spring,那麼當Action需要使用UserServiceImpl時,必須通過“UserService userService = new UserServiceImpl();”主動去建立例項物件,但使用了Spring之後,Action要使用UserServiceImpl時,就不用主動去建立UserServiceImpl的例項了,建立UserServiceImpl例項已經交給Spring來做了,Spring把建立好的UserServiceImpl例項給Action,Action拿到就可以直接用了。Action由原來的主動建立UserServiceImpl例項後就可以馬上使用,變成了被動等待由Spring建立好UserServiceImpl例項之後再注入給Action,Action才能夠使用。這說明Action對“UserServiceImpl”類的“控制權”已經被“反轉”了,原來主動權在自己手上,自己要使用“UserServiceImpl”類的例項,自己主動去new一個出來馬上就可以使用了,但現在自己不能主動去new“UserServiceImpl”類的例項,new“UserServiceImpl”類的例項的權力已經被Spring拿走了,只有Spring才能夠new“UserServiceImpl”類的例項,而Action只能等Spring建立好“UserServiceImpl”類的例項後,再“懇求”Spring把建立好的“UserServiceImpl”類的例項給他,這樣他才能夠使用“UserServiceImpl”,這就是Spring核心思想“控制反轉”,也叫“依賴注入”,“依賴注入”也很好理解,Action需要使用UserServiceImpl幹活,那麼就是對UserServiceImpl產生了依賴,Spring把Acion需要依賴的UserServiceImpl注入(也就是“給”)給Action,這就是所謂的“依賴注入”。對Action而言,Action依賴什麼東西,就請求Spring注入給他,對Spring而言,Action需要什麼,Spring就主動注入給他。
beans.xml'
print?在CODE上檢視程式碼片派生到我的程式碼片
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"  
  4.     xmlns:context="http://www.springframework.org/schema/context"  
  5.     xsi:schemaLocation="http://www.springframework.org/schema/beans    
  6.                 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    
  7.         http://www.springframework.org/schema/context    
  8.         http://www.springframework.org/schema/context/spring-context-3.0.xsd">  
  9.      <!-- 配置的bean所在包的位置 -->    
  10.     <context:component-scan base-package="com.mucfc" />  
  11. </beans>  
測試下: print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.mucfc.anno;  
  2. import org.springframework.context.ApplicationContext;  
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  4. import com.mucfc.model.User;  
  5. import com.mucfc.service.UserService;  
  6. public class Test {  
  7.     public static void main(String[] args) {  
  8.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");  
  9.         UserService service=(UserService)applicationContext.getBean("userService");  
  10.         User user1 = (User) applicationContext.getBean("user");   
  11.         User user2 = (User) applicationContext.getBean("user");  
  12.         user1.setName("小明");  
  13.         user1.setSex("男");  
  14.         user1.setAge(22);  
  15.         user2.setName("小紅");  
  16.         user2.setSex("女");  
  17.         user2.setAge(18);  
  18.         service.add(user1);  
  19.         service.add(user2);  
  20.     }  
  21. }  
[java] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片
  1. package com.mucfc.anno;  
  2. import org.springframework.context.ApplicationContext;  
  3. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  4. import com.mucfc.model.User;  
  5. import com.mucfc.service.UserService;  
  6. public class Test {  
  7.     public static void main(String[] args) {  
  8.         ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");  
  9.         UserService service=(UserService)applicationContext.getBean("userService");  
  10.         User user1 = (User) applicationContext.getBean("user");   
  11.         User user2 = (User) applicationContext.getBean("user");  
  12.         user1.setName("小明");  
  13.         user1.setSex("男");  
  14.         user1.setAge(22);  
  15.         user2.setName("小紅");  
  16.         user2.setSex("女");  
  17.         user2.setAge(18);  
  18.         service.add(user1);  
  19.         service.add(user2);  
  20.     }  
  21. }  
package com.mucfc.anno;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mucfc.model.User;
import com.mucfc.service.UserService;


public class Test {

	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
		UserService service=(UserService)applicationContext.getBean("userService");
		User user1 = (User) applicationContext.getBean("user"); 
		User user2 = (User) applicationContext.getBean("user");
		user1.setName("小明");
		user1.setSex("男");
		user1.setAge(22);
		
		user2.setName("小紅");
		user2.setSex("女");
		user2.setAge(18);
		
		service.add(user1);
		service.add(user2);
	}

}
結果:


當在元件類中使用了特定的註解之後,還需要在Spring的配置檔案中宣告 <context:component-scan>:

  • base-package屬性指定一個需要掃描的基類包,Spring容器將會掃描整個基類包裡及其子包中的所有類
  • 當需要掃描多個包時,可以使用逗號分隔
  • 如果僅希望掃描特定的類而非基包下的所有類,可使用resource-pattern屬性過濾特定的類,例項:  
  • <context:include-filter>子節點表示要包含的目標類
  • <context:exclude-filter>子節點表示要排除在外的目標類
  • <context:component-scan>下可以擁有若干個<context:include-filter>和<context:exclude-filter>子節點
  • <context:include-filter>和<context:exclude-filter>子節點支援多種型別的過濾表