spring-boot注解詳解(一)
@SpringBootApplication
@SpringBootApplication = (默認屬性)@Configuration + @EnableAutoConfiguration + @ComponentScan。
- @Configuration:提到@Configuration就要提到他的搭檔@Bean。使用這兩個注解就可以創建一個簡單的spring配置類,可以用來替代相應的xml配置文件。
<beans> <bean id = "car" class="com.test.Car"> <property name="wheel" ref = "wheel"></property> </bean> <bean id = "wheel" class="com.test.Wheel"></bean>
</beans>
相當于:
@Configuration
public class Conf { @Bean public Car car() { Car car = new Car(); car.setWheel(wheel()); return car; } @Bean public Wheel wheel() { return new Wheel(); }
}
@Configuration的注解類標識這個類可以使用Spring IoC容器作為bean定義的來源。@Bean注解告訴Spring,一個帶有@Bean的注解方法將返回一個對象,該對象應該被注冊為在Spring應用程序上下文中的bean。
2、@EnableAutoConfiguration:能夠自動配置spring的上下文,試圖猜測和配置你想要的bean類,通常會自動根據你的類路徑和你的bean定義自動配置。
3、@ComponentScan:會自動掃描指定包下的全部標有@Component的類,并注冊成bean,當然包括@Component下的子注解@Service,@Repository,@Controller。
@EnableTransactionManagement
@EnableTransactionManagement 開啟事務支持后,然后在訪問數據庫的Service方法上添加注解 @Transactional 便可。
關于事務管理器,不管是JPA還是JDBC等都實現自接口 PlatformTransactionManager 如果你添加的是 spring-boot-starter-jdbc 依賴,框架會默認注入 DataSourceTransactionManager 實例。如果你添加的是 spring-boot-starter-data-jpa 依賴,框架會默認注入 JpaTransactionManager 實例。
你可以在啟動類中添加如下方法,Debug測試,就能知道自動注入的是 PlatformTransactionManager 接口的哪個實現類。
@EnableTransactionManagement // 啟注解事務管理,等同于xml配置方式的 <tx:annotation-driven />
@SpringBootApplication
public class ProfiledemoApplication {@Beanpublic Object testBean(PlatformTransactionManager platformTransactionManager){System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());return new Object();}public static void main(String[] args) {SpringApplication.run(ProfiledemoApplication.class, args);}
這些SpringBoot為我們自動做了,這些對我們并不透明,如果你項目做的比較大,添加的持久化依賴比較多,我們還是會選擇人為的指定使用哪個事務管理器。
代碼如下:
@EnableTransactionManagement
@SpringBootApplication
public class ProfiledemoApplication {// 其中 dataSource 框架會自動為我們注入@Beanpublic PlatformTransactionManager txManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Beanpublic Object testBean(PlatformTransactionManager platformTransactionManager) {System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());return new Object();}public static void main(String[] args) {SpringApplication.run(ProfiledemoApplication.class, args);}
}
在Spring容器中,我們手工注解@Bean 將被優先加載,框架不會重新實例化其他的 PlatformTransactionManager 實現類。
然后在Service中,被 @Transactional 注解的方法,將支持事務。如果注解在類上,則整個類的所有方法都默認支持事務。
對于同一個工程中存在多個事務管理器要怎么處理,請看下面的實例,具體說明請看代碼中的注釋。
@EnableTransactionManagement // 開啟注解事務管理,等同于xml配置文件中的 <tx:annotation-driven />
@SpringBootApplication
public class ProfiledemoApplication implements TransactionManagementConfigurer {@Resource(name="txManager2")private PlatformTransactionManager txManager2;// 創建事務管理器1@Bean(name = "txManager1")public PlatformTransactionManager txManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}// 創建事務管理器2@Bean(name = "txManager2")public PlatformTransactionManager txManager2(EntityManagerFactory factory) {return new JpaTransactionManager(factory);}// 實現接口 TransactionManagementConfigurer 方法,其返回值代表在擁有多個事務管理器的情況下默認使用的事務管理器@Overridepublic PlatformTransactionManager annotationDrivenTransactionManager() {return txManager2;}public static void main(String[] args) {SpringApplication.run(ProfiledemoApplication.class, args);}}
@Component
public class DevSendMessage implements SendMessage {// 使用value具體指定使用哪個事務管理器@Transactional(value="txManager1")@Overridepublic void send() {System.out.println(">>>>>>>>Dev Send()<<<<<<<<");send2();}// 在存在多個事務管理器的情況下,如果使用value具體指定// 則默認使用方法 annotationDrivenTransactionManager() 返回的事務管理器@Transactionalpublic void send2() {System.out.println(">>>>>>>>Dev Send2()<<<<<<<<");}}
注:
如果Spring容器中存在多個 PlatformTransactionManager 實例,并且沒有實現接口 TransactionManagementConfigurer 指定默認值,在我們在方法上使用注解 @Transactional 的時候,就必須要用value指定,如果不指定,則會拋出異常。
對于系統需要提供默認事務管理的情況下,實現接口 TransactionManagementConfigurer 指定。
對有的系統,為了避免不必要的問題,在業務中必須要明確指定 @Transactional 的 value 值的情況下。不建議實現接口 TransactionManagementConfigurer,這樣控制臺會明確拋出異常,開發人員就不會忘記主動指定。
@Controller
@Controller用于標記在一個類上,使用它標記的類就是一個SpringMvc Controller對象,分發處理器會掃描使用該注解的類的方法,并檢測該方法是否使用了@RequestMapping注解。
@Controller只是定義了一個控制器類,而使用@RequestMapping注解的方法才是處理請求的處理器。
@Controller標記在一個類上還不能真正意義上說它就是SpringMvc的控制器,應為這個時候Spring還不認識它,這個時候需要把這個控制器交給Spring來管理。有兩種方式可以管理:
<!--基于注解的裝配-->
<!--方式一-->
<bean class="com.HelloWorld"/>
<!--方式二-->
<!--路徑寫到controller的上一層-->
<context:component-scan base-package="com"/>
Action層:
package com;
@Controller
public class HelloWorld{@RequestMapping(value="/showRegUser")public String printHello() {return "hello";}@Autowriedprivate IocSerevce service;public void add(){service.add();}
}
component-scan默認掃描的注解類型是@Component,不過,在@Component的語義基礎之上細化為@Reposity,@Service,@Controller.
有一個use-defaultbao’i-filters屬性,屬性默認是true,表示會掃描抱下所有的標有@Component的類,并注冊為bean,也就是@Component的子注解@Service,@reposity等
如果只想掃描包下的@Controller或其他內容,則設置use-default-filters屬性為false,表示不再按照scan指定的包進行掃描,而是按照指定包進行掃描
<context:component-scan base-package="com" user-default-filters="false"><context:include-filter type="regex" expression="com.tan.*"/>
</context:component-scan>
當沒有設置use-default-filters屬性或屬性為true時,表示基于base-package包下指定掃描的具體路徑。
@RequestMapping
RequestMapping是一個用來處理請求地址映射的注解,可用于類或方法上。用于類上,表示類中的所有響應請求的方法都是以該地址作為父路徑。
RequestMapping注解有六個屬性,下面我們把她分成三類進行說明。
1.value, method;
value: 指定請求的實際地址,指定的地址可以是URI Template 模式(后面將會說明);
method: 指定請求的method類型, GET、POST、PUT、DELETE等;
默認 RequestMapping(“url”)即為value的值;
顯式說明 RequestMapping(value=”url”)
@Controller
@RequestMapping("/appointments")
public class AppointmentsController {private AppointmentBook appointmentBook;@Autowiredpublic AppointmentsController(AppointmentBook appointmentBook) {this.appointmentBook = appointmentBook;}@RequestMapping(method = RequestMethod.GET)public Map<String, Appointment> get() {return appointmentBook.getAppointmentsForToday();}@RequestMapping(value="/{day}", method = RequestMethod.GET)public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {return appointmentBook.getAppointmentsForDay(day);}@RequestMapping(value="/new", method = RequestMethod.GET)public AppointmentForm getNewForm() {return new AppointmentForm();}@RequestMapping(method = RequestMethod.POST)public String add(@Valid AppointmentForm appointment, BindingResult result) {if (result.hasErrors()) {return "appointments/new";}appointmentBook.addAppointment(appointment);return "redirect:/appointments";}
}
value的url值為以下三類:
A) 可以指定為普通的具體值;
B) 可以指定為含有某變量的一類值(URI Template Patterns with Path Variables);
C) 可以指定為含正則表達式的一類值( URI Template Patterns with Regular Expressions);
example B)@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(@PathVariable String ownerId, Model model) {Owner owner = ownerService.findOwner(ownerId); model.addAttribute("owner", owner); return "displayOwner";
}
example C)@RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\d\.\d\.\d}.{extension:\.[a-z]}")public void handle(@PathVariable String version, @PathVariable String extension) { // ...}
}
2.consumes,produces;
consumes: 指定處理請求的提交內容類型(Content-Type),例如application/json, text/html;
produces: 指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回;
@Controller
@RequestMapping(value = "/pets", method = RequestMethod.POST, consumes="application/json")
public void addPet(@RequestBody Pet pet, Model model) { // implementation omitted
}
方法僅處理request Content-Type為“application/json”類型的請求。produces的樣例:@Controller
@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, produces="application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) { // implementation omitted
}
方法僅處理request請求中Accept頭中包含了”application/json”的請求,同時暗示了返回的內容類型為application/json;
3.params,headers;
params: 指定request中必須包含某些參數值是,才讓該方法處理。
headers: 指定request中必須包含某些指定的header值,才能讓該方法處理請求。
@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET, params="myParam=myValue")public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted}
}
僅處理請求中包含了名為“myParam”,值為“myValue”的請求;
headers的樣例:
@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {@RequestMapping(value = "/pets", method = RequestMethod.GET, headers="Referer=http://www.ifeng.com/")public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) { // implementation omitted}
}