先說一下什么是組件掃描:
指定一個包路徑,Spring會自動掃描該包及其子包所有組件類,當發現組件類定義前有特定的注解標記時,就將該組件納入到Spring容器。等價於原有XML配置中的<bean>定義功能。
組件掃描可以替代大量XML配置的<bean>定義。
使用組件掃描,首先需要在XML配置中指定掃描類路徑:
<context:component-scan
base-package = "org.example"/>
上面配置,容器實例化時會自動掃描org.example包及其子包下所有組件類。
指定掃描類路徑后,並不是該路徑下所有組件類都掃描到Spring容器的,只有在組件類定義前面有以下注解標記時,才會掃描到Spring容器。
@Component:通用注解;@Name:通用注解;@Repository:持久化層組件注解
@Service:業務層組件注解;@Controller:控制層組件注解
當一個組件在掃描過程中被檢測到時,會生成一個默認id值,默認id為小寫開頭的類名。也可以在注解標記中自定義id。下面兩個組件id名字分別是oracleUserDao和loginService
@Repository
public class OracleUserDao implements UserDao{
//.....
}
@Service("loginService")
public class UserService{
//....
}
通常受Spring管理的組件,默認的作用域是“singleton”。如果需要其他作用域可以使用@Scope注解,只要在注解中提供作用域的名稱即可。
@Scope("prototype")
@Repository
public class OracleUserDao implements EmpDao{
//...
}
@PostConstruct和@PreDestroy注解標記分別用於指定初始化和銷毀回調方法,使用示例:
public class ExampleBean{
@PostConstruct
public void init(){
//初始化回調方法
}
@PreDestroy
public void destroy(){
//銷毀回調方法
}
}
具有依賴關系的Bean對象,利用下面任何一種注解都可以實現關系注入:
@Resource
@Autowired/@Qualifier
@Inject/@Named
@Resource注解標記可以用在字段定義或setter方法定義前面,默認首先按名稱匹配注入,然后類型匹配注入:
public class UserService{
//@Resource
private UserDao userDao;
@Resource
public void setUserDao(UserDao dao){
this.userDao = dao;
}
}
當遇到多個匹配Bean時注入會發生錯誤,可以顯示指定名稱,例如@Resource(name = "empDao1")
@Autowired注解標記也可以用在字段定義或setter方法定義前面,默認按類型匹配注入:
public class UserService{
//@Autowired
private UserDao userDao;
@Autowired
public void setUserDao(UserDao dao){
this.userDao = dao;
}
}
@Autowired當遇到多個匹配Bean時注入會發生錯誤,可以使用下面方法指定名稱:
public class UserService{
//@Autowired
//@Qualifiter("mysqlUserDao")
private UserDao userDao;
@Autowired
public void setUserDao(@Qualifiter("mysqlUserDao") userDao dao){
this.userDao = dao;
}
}
@Inject注解標記是Spring3.0開始增添的對JSR-330標准的支持,使用前需要添加JSR-330的jar包,使用方法與@Autowired相似,具體如:
public class UserService{
//@Inject
private UserDao userDao;
@Inject
public void setUserDao(UserDao dao){
this.userDao = dao;
}
}
@Inject當遇到多個匹配Bean時注入會發生錯誤,可以使用@Named指定名稱限定,使用方法為:
public class UserService{
private UserDao userDao;
@Inject
public void setUserDao(@Named("mysqlUserDao") UserDao dao){
this.userDao = dao;
}
}
@Value注解可以注入Spring表達式值,使用方法:
首先在XML配置中指定要注入的properties文件
<util:properties id = "jdbcProps" location = "classpath:db.properties"/>
然后在setter方法前使用@Value注解
public class JDBCDataSource{
@Value("#{jdbcProps.url}")
private String url;
@Value("#{jdbcProps.driver}")
public void setUrl(String driver){
try{Class.forName(driver)}catch(.....)...
}
}
RequestMapping注解應用
@RequestMapping可以用在類定義和方法定義上
@RequestMapping標明這個類或者方法與哪一個客戶請求對應
@RequestMapping可以定義在Controller類前和處理方法前,主要用於指定Controller的方法處理哪些請求
@Controller
@RequestMapping("/demo01")
public class Controller{
@RequestMapping("/hello")
public String execute()throws Exception{
return "hello";
}
}
開啟@RequestMapping注解映射,需要在Spring的XML配置文件中定義RequestMappingHandlerMapping(類定義前)和RequestMappingHandlerAdapter(方法定義前)兩個bean組件
示例:
<bean
class ="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<bean
class = "org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
從Spring3.2版本開始可以使用下面XML配置簡化RequestMappingHandlerMapping和RequestMappingHandlerAdapter定義:
<mvc:annotation-driven/>
Controller注解應用
推薦使用@Controller注解聲明Controller組件,這樣可以使得Controller定義更加靈活,可以不用實現Controller接口,請求處理的方法也可以靈活定義
@Controller
@RequestMapping("/demo01")
public classs Controller{
@RequestMapping("/hello")
public String execute()throws Exception{
return "hello";
}
}
為了使@Controller注解生效,需要在Spring的XML配置文件中開啟組件掃描定義,並指定Controller組件所在包
<context:component-scan base-package = "com.controller"/>
接受請求參數值
Spring MVC Web請求提交數據到控制器有下面幾種方法:
使用 HttpServletRequest獲取
使用@RequestParam注解
使用自動機制封裝成Bean對象
使用@RequestParam注解:
Spring會自動將表單參數注入到方法參數(名稱一致)
使用@RequestParam注解,映射不一致的名稱
優點參數類型會自動轉換,但可能出現類型轉換異常
@RequestMapping("/login-action.form")
public String checkLogin(String name,@RequestParam("pwd")String password,HttpServletRequest req){
System.out.println(name);
System.out.println(password);
User user = userService.login(name,password);
//處理過程
return "success";
使用@ModelAttribute注解是當Controller組件處理后,需要向JSP傳值用此方法。
(引出:向JSP頁面傳值也可以直接使用HttpServletRequest和Session;ModeAndView對象;ModelMap參數對象等)
示例:
在Controller方法的參數部分或Bean屬性方法上使用。
@RequestMapping("login-action.from")
public String checkLogin(@ModelAttribute("user")User user){
//處理過程
return "success";
}
@ModelAttribute("name")
public String getName(){
return name;
}
(@ModelAttribute數據會利用HttpServletRequest的Attribute傳遞到JSP頁面中)
@ExceptionHandler注解
@ExceptionHandler注解提供了Spring MVC處理異常的方法
(引出:Spring MVC處理異常的方法有三種:使用Spring MVC提供的簡單異常處理器(SimpleMappingExceptionResolver);實現HandlerExceptionResolver接口自定義異常處理器;使用 @ExceptionHandler注解實現異常處理)
@ExceptionHandler注解使用方法:
public class BaseController{
@ExceptionHandler
public String execute(HttpServletRequest req,Exception e){
req.setAttribute("e",e);
//可根據異常類型不同返回不同視圖名
return "error";
}
}
(適合局部處理有“處理過程”的異常)
然后其他的Controller繼承BaseController類即可
@ResponseBody注解(在Spring MVC中,此注解與JSON響應相關)
在控制器方法上使用 @ResponseBody 注解, 就可以自動的將控制器的返回值(JavaBean)轉換為JSON發送到客戶端.
@ResponseBody注解主要用於Controller組件的處理方法前,使用方法為:
引入jackson開發包,后面示例用的是jackson-annotations-2.4.1.jar,jackson-core-2.4.1.jar,jackson-databind-2.4.1.jar
在Spring配置文件中定義<mvc:annotation-driven/>,開啟對@ResponseBody應用的支持
在Controller處理方法前定義@ResponseBody注解
示例:
使用@ResponseBody,返回單個值:
@RequestMapping("/test1")
@ResponseBody
public boolean f1(){
//業務處理代碼
return true;
}
使用@ResponseBody返回多個值:
@RequestMapping("/test2")
@ResponseBody
public Map<String,Object>f2(){
Map<String,Object> m = new HashMap<String,Object>)();
m.put("id",1);
m.put("name","Tom");
return m;
}
使用@ResponseBody返回List結果:
@RequestMapping("/test3")
@ResponseBody
public List<String>f3(){
List<String> list = new ArrayList<String>();
list.add("java");
list.add("php");
list.add("ui");
return list;
}
使用@ResponseBody返回對象結果:
@RequestMapping("/test4")
@ResponseBody
public Object f4(){
Object obj = new Object();
return obj;
}
使用@ResponseBody返回對象集合結果:
@RequestMapping("/test5")
@ResponseBody
public Object f5(){
Emp e1 = new Emp();
e1.setId(1);
e1.setName("張三");
Emp e2 = new Emp();
e2.setId(2);
e2.setName("李四");
List<Emp> list = new ArrayList<Emp>();
list.add(e1);
;ist.add(e2);
return list;
}
注解實現AOP
開發步驟:
創建方面組件:
創建一個類,充當方面組件,實現通用業務邏輯。
聲明方面組件:
在applicationContext.xml中開啟AOP注解掃描:
<aop:aspectj-autoproxy proxy-target-class = "true"/>;
使用@Component注解標識這個類,將其聲明為組件。
使用@Aspect注解標識這個類,將其聲明為方面組件。
使用方面組件:
在組件的方法上,使用注解將方面組件作用到目標組件的方法上,並設置通知類型以確認方面組件調用的時機。
使用前置通知,在方面組件方法上增加注解:
@Before("within(controller..*)")
public void log(){
}
后置通知、最終通知使用方法與前置通知一致,只需要將注解改為@AfterReturning、@After即可。
環繞通知,在方面組件方法上增加注解:
@Around("within(controller..*)")
public Object log(ProceedingJoinPoint p) throws Throwable{
//此處代碼在目標組件前執行
Object obj = p.proceed();//執行目標組件方法
//此處代碼在目標組件后執行
return obj;
}
使用異常通知,在方面組件方法上增加注解:
@AfterThrowing(pointcut = "within(controller..*)",throwing = "e")
public void log(Exception e){
}
@Transactional注解
此注解實現聲明式事務,步驟如下:
在applicationContext.xml中聲明事務組件,開始事務注解掃描,示例為:
<!-- 聲明事務管理組件 -->
<bean id = "txManager"
class = "org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name = "dataSource" ref = "ds"/>
</bean>
<!-- 開啟事務注解掃描 -->
<tx:annotation-driven transaction-manager = "txManager" proxy-target-class = "true"/>
transaction-manager指定的事務管理器txManager,需要根據數據庫訪問技術不同選擇不同的實現。例如JDBC、Mybatis技術選用DataSourceTransactionManager,而Hibernate技術則選用HibernateTransactionManager.
使用 @Transactional注解聲明事務,使用方法為:
@Transactional
public class DefaultFooService implements FooService{
// @Transactional
public void insertFoo(Foo foo){...}
public void updateFoo(Foo foo){...}
@Transactional注解標記可以用在類定義和方法定義前,方法的事務設置將優先於類級別注解的事務設置。
@Transactional注解標記有以下屬性,在使用時可以根據需要做特殊設定:
- propagation:設置事務傳播
- isolation:設置事務隔離級別
- readOnly:設置為只讀,還是可讀寫
- rollbackFor:設置遇到哪些異常必須回滾
- noRollbackFor:設置遇到哪些異常不回滾
@Transactional注解屬性默認設置如下:
事務傳播設置是:PROPAGATION_REQUIRED
事務隔離級別是:ISOLATION_DEFAULT
事務是讀/寫
事務超時默認是依賴於事務系統的,或者事務超時沒有被支持
任何RuntimeException將觸發事務回滾,但是任何Checked Exception將不觸發事務回滾
@PathVariable應用
@PathVariable作用是將URI請求模板中的變量解析出來,映射到處理方法的參數上,示例為:
@RequestMapping(value = "/emp/{id}",method = requestMethod.GET)
public String execute(@PathVariable("id") int id){
//查詢操作處理
return " ";
}
上述URI請求模板匹配/emp/1、emp/2等格式請求
暫時總結的常用的注解方面的概述就這樣了,還有一些未總結,能看懂就好了。
