Spring IOC/DI 相關注解
- @Configuration 等價於applicationContext.xml配置
@Configuration
public class ApplicationConfig {
//...
}
使用程序實現加載工廠
AnnotationConfigApplicationContext ctx= new AnnotationConfigApplicationContext(ApplicationConfig.class);
老版本編寫
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
使用程序實現加載工廠
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
- @Bean 等價 標籤
@Bean(name="date")
public Date getDate() {
return new Date();
}
等價
<bean id="date" class="java.util.Date"</bean>
@Bean屬性介紹
屬性名 | 類型 | 是否必須 | 說明 |
---|---|---|---|
name | String | 否 | 等價於<bean /> 的id屬性,不可以和value同時出現 |
value | String | 否 | 等價於<bean /> 的id屬性,不可以和name同時出現 |
autowire | Bean | 否 | 自動注入方式Autowire.NO/BY_NAME/BY_TYPE |
destroyMethod | String | 否 | 等價於<bean /> 的destroy-method屬性 |
init-method | String | 否 | 等價於<bean /> 的init-method屬性 |
- @Component 、@Service、@Repository、@Controller
以上註解主要面向分層開發時候需要對不同層次的Bean分類管理。
@Service("userService")
public class UserService implements IUserService{
}
- @ComponentScan
該註解用於掃描指定spring容器的bean,並且將掃描的bean放置到Spring工廠中。
@Configuration
@ComponentScan(basePackages="com.baizhi",
excludeFilters= {
@Filter(type=FilterType.ANNOTATION,value=Controller.class)
},
includeFilters= {
@Filter(Service.class),
@Filter(Repository.class)
}
)
public class ApplicationConfig {
//...
}
等價寫法
<context:component-scan base-package="com.baizhi">
<context:include-filter
type="annotation"
expression="org.springframework.stereotype.Repository,
org.springframework.stereotype.Service"/>
<context:exclude-filter
type="annotation"
expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
- Bean生命週期控制@PreDestroy、@PostConstruct、@Scope
@Component("otherComponent")
@Scope(value=BeanDefinition.SCOPE_PROTOTYPE|SCOPE_SINGLETON)
public class OtherComponent {
public OtherComponent() {
// TODO Auto-generated constructor stub
}
@PostConstruct
public void init() {
System.out.println("init...");
}
@PreDestroy
public void destory() {
System.out.println("destory...");
}
}
默認Spring工廠管理的Bean都是單例的,同時Spring會在工廠初始化的時候就創建配置的組件bean。這個時候如果想在工廠創建或者工廠消亡的時候執行某些方法時候,可以考慮添加@PostConstruct、@PreDestroy註解即可。
等價寫法
<bean id="otherComponent" class="com.baizhi.other.OtherComponent"
scope="prototype|singleton"
init-method="init"
destroy-method="destory"/>
- @Lazy
表示延遲spring工廠初始化Bean等價 beans標籤的default-lazy-init="true"屬性
@Configuration
@Lazy
public class ApplicationConfig {
}
- @Autowired、@Resource、@Inject、@Qualifier、@Primary
@Bean(name="date1")
public Date getDate1() {
return new Date();
}
@Bean(name="date2")
public Date getDate2() {
return new Date();
}
@Bean("date3")
public Date date(@Qualifier("date1")Date date) {
System.out.println("000000000");
return date;
}
@Bean管理的Bean的參數默認是自動注入的,此時如果發現有兩個相同類型的Bean出現就會導致注入失敗,解決之道是使用@Qualifier註解指定注入的參數當然也可以使用@Primary指定默認參與注入的類型。
@Bean(name="date1")
@Primary
public Date getDate1() {
return new Date();
}
@Bean(name="date2")
public Date getDate2() {
return new Date();
}
@Bean("date3")
public Date date(Date date) {
System.out.println("000000000");
return date;
}
@Autowired和@Resource都是解決Spring的值注入的不同的是@Autowired按照類型注入,此時如果容器存在兩個相同類型的Bean組件的時候此時注入則是失敗的。這個時候需要和@Qulifier或者@Primary註解聯合使用解決類型衝突問題;@Resource註解是JDK1.6主持的註解該註解一旦指定name之後只會按照name注入如果沒有指定name屬性,先按照name注入如果查找不到再按照類型注入。@Inject和@Autowired用法一致但是使用@Inject需要導入額外的Maven依賴,而且如果存在類型衝突需要使用@Named註解指明需要注入的組件名字
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
- @Required
該屬性用於作用在set方法上表明在初始化該Bean的時候,該set個方法的屬性必須設置值。一般和配置文件聯合使用
public class UserService implements IUserService{
private Date date;
public Date getDate() {
return date;
}
@Required
public void setDate(Date date) {
this.date = date;
}
}
配置文件
<context:annotation-config/>
<bean id="userService" class="com.baizhi.service.impl.UserService">
<property name="date">
<bean class="java.util.Date"></bean>
</property>
</bean>
注意必須配置context:annotation-config/屬性,否則@Required不起作用
- @ImportResource(引入xml配置)
@Configuration
@ImportResource(value= {"classpath:applicationContext.xml"})
public class ApplicationConfig {
}
- @Import(引入配置類)
@Configuration
public class ConfigA {
@Bean
public A a() {
return new A();
}
}
@Configuration
@Import(ConfigA.class)
public class ConfigB {
@Bean
public B b() {
return new B();
}
}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(ConfigB.class);
// now both beans A and B will be available...
A a = ctx.getBean(A.class);
B b = ctx.getBean(B.class);
}
- @Profile
@Configuration
@Import(value= {DevConfig.class,ProConfig.class})
public class ApplicationConfig {
}
-----------------------
@Configuration
@ImportResource(value= {"classpath:applicationContext.xml"})
@Profile("dev")
public class DevConfig {
}
-----------------------
@Configuration
@Profile("pro")
public class ProConfig {
}
測試環境
AnnotationConfigApplicationContext ctx= new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("pro");
ctx.register(ApplicationConfig.class);
ctx.refresh();
System.out.println(ctx.getBean("userService"));
ctx.close();
- @ImportResource(引入外部配置資源)
@Configuration
@ImportResource("classpath:/com/acme/properties-config.xml")
public class AppConfig {
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
return new DriverManagerDataSource(url, username, password);
}
}
properties-config.xml
<beans>
<context:property-placeholder location="classpath:/com/acme/jdbc.properties"/>
</beans>
jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=root
@AspectJ相關注解
@AspectJ是一種aspects 的風格,它是用註釋註釋的常規Java類。
該註解用於開啓**@AspactJ**支持
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "com.baizhi")
public class AopConfig {
}
等價寫法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
該註解用於聲明切面類
@Aspect
@Component
public class AspectModule {
}
該註解用於聲明切入點
@Pointcut("execution(* com.baizhi..*.*(..))") // 切入點表達式
public void pc(){}
常用的切入點標誌符
切入點標誌符 | 說明 |
---|---|
execution | 匹配執行方法的連接點 |
within | 限定匹配特定類型的連接點 |
this | 用於指定AOP代理必須是指定類型的實例,用於匹配該對象的所有連接點 |
target | 用於限定目標對象必須是指定類型的實例,用於匹配該對象的所有連接點 |
args | 用於對連接點的參數類型進行限制,要求參數的類型時指定類型的實例 |
@annotation | 用於對連接點的註解類型進行限制,要求註解的類型爲指定類型的實例 |
該註解用於聲明前置通知
@Aspect
public class AspectModule {
@Pointcut("execution(* com.baizhi..*.*(..))")
public void pc(){}
// 參數爲切入點方法名(好處,定義一個切入點實現複用)
@Before("pc()")
// JoinPoint 用於獲取連接點信息(如獲取方法和類信息)
public void before(JoinPoint joinPoint){
System.out.println("-------------before advice-----------");
}
}
老版本寫法
public class MyBeforeAdvice implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("-------------before advice-----------");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.baizhi.service.UserServiceImpl"></bean>
<bean id="beforeAdvice" class="MyBeforeAdvice"></bean>
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.baizhi..*.*(..))"></aop:pointcut>
<aop:advisor advice-ref="beforeAdvice" pointcut-ref="pc"></aop:advisor>
</aop:config>
</beans>
該註解用於聲明匹配方法正常返回的後置通知
@AfterReturning("pc()")
public void afterReturning(){
System.out.println("-------------after returning advice-----------");
}
正常返回
非正常返回
該註解用於聲明異常通知(目標方法產生異常執行的代碼片段)
@AfterThrowing("pc()")
public void afterThrowing(){
System.out.println("-------------after throwing advice-----------");
}
切入方法拋出異常
該註解用於聲明後置通知(無論目標方法是否產生異常都會執行的代碼片段)
@After("pc()")
public void after(){
System.out.println("-------------after advice-----------");
}
該註解用於聲明環繞通知(在調用目標方法前後執行)
@Around("pc()")
// 注意:參數ProceedingJoinPoint只能適用於環繞通知,用於獲取連接點信息
public void aroud(ProceedingJoinPoint pjp){
System.out.println("-------------aroud advice start-----------");
try {
// 調用目標方法 並獲取目標方法返回值
Object proceed = pjp.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println("-------------aroud advice end-----------");
}
該註解用於指定多切面執行順序(@Order值越小優先級越高)
@Aspect
@Component
@Order(1)
public class AspectModule {
@Pointcut("execution(* com.baizhi..*.*(..))")
public void pc(){}
@Before("pc()")
public void before1(JoinPoint joinPoint){
System.out.println("------before1 advice first execute-----");
}
}
@Aspect
@Component
@Order(5)
public class AspectModule1 {
@Pointcut("execution(* com.baizhi..*.*(..))")
public void pc(){}
@Before("pc()")
public void before2(JoinPoint joinPoint){
System.out.println("------before2 advice second execute-----");
}
}
老版本寫法
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.baizhi..*.*(..))"></aop:pointcut>
<aop:advisor advice-ref="beforeAdvice1" pointcut-ref="pc" order="1"></aop:advisor>
<aop:advisor advice-ref="beforeAdvice2" pointcut-ref="pc" order="5"></aop:advisor>
</aop:config>
Spring MVC相關注解
該註解用於開啓基於註解的MVC支持
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.baizhi")
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// TODO Auto-generated method stub
registry.addResourceHandler("/**")
.addResourceLocations("/")
.setCachePeriod(1000000);
}
}
老版本寫法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
啓動引導類
/**
* @author gaozhy
* @date 2018/4/8.11:18
*/
public class WebInitializer implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(MvcConfig.class);
ctx.setServletContext(servletContext);
ServletRegistration.Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.addMapping("/");
servlet.setLoadOnStartup(1);
}
}
該註解指示特定的類充當控制器的角色
@Controller
public class HelloController {
}
該註解爲組合註解@Controller和@ResponseBody(控制器實現REST API,響應JSON、XML或自定義的MediaType內容。無需用@ResponseBody註釋所有的@RequestMapping方法。),用於構建Restful風格的控制器類
@RestController
public class RestfulController {
}
@RequestMapping(value = "/",method = RequestMethod.GET)
public String index(){
return "Hello World";
}
以下註解用於簡化HTTP方法的映射,並更好地表達帶註釋的處理程序方法的語義。例如,@GetMapping 等同於@RequestMapping(method = RequestMethod.GET)
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
該註解放在方法參數前,用於綁定URL中攜帶的Value
/**
* 例如:http://localhost:8080/owners/1
*/
@GetMapping("/owners/{ownerId}")
@ResponseBody
public String findOwner(@PathVariable String ownerId) {
System.out.println(ownerId);
return ownerId;
}
用法一:應用在普通方法上
被 @ModelAttribute 註解的方法會在Controller每個目標方法執行之前都執行(注:對於一個Controller中包含多個URL的時候,要謹慎使用),並且會將返回值自動存儲到Model中(key默認爲首字母小寫的返回值名,value爲方法返回值)
/**
* 例如:http://localhost:8080/owners/1
*/
@GetMapping("/owners/{ownerId}")
@ResponseBody
public String findOwner(@PathVariable String ownerId) {
System.out.println(ownerId);
return ownerId;
}
@ModelAttribute
public User getUser(){
System.out.println("----------進入到 getUser method----------");
return new User(1,"張三");
}
@ModelAttribute
public Person getPerson(){
System.out.println("----------進入到 getPerson method----------");
return new Person(1,"李四","北京");
}
在請求http://localhost:8080/owners/1,會依次訪問getUser、getPerson,然後再去訪問目標方法findOwner,被@ModelAttribute註解的方法的返回值會自動添加到Model中保存起來。
類似於
@GetMapping("/owners/{ownerId}")
@ResponseBody
public String findOwner(@PathVariable String ownerId,Model model) {
model.addAttribute("user",new User(1,"張三"));
model.addAttribute("person",new Person(1,"李四","北京"));
System.out.println(ownerId);
return ownerId;
}
- 用法二:應用在方法的參數上
將Model中Key對應的Value綁定給指定參數
@ModelAttribute
public User getUser(){
System.out.println("----------進入到 getUser method----------");
return new User(1,"張三");
}
@ModelAttribute
public Person getPerson(){
System.out.println("----------進入到 getPerson method----------");
return new Person(1,"李四","北京");
}
@GetMapping("/test")
@ResponseBody
public String test(@ModelAttribute("user")User user,@ModelAttribute("person")Person person) {
System.out.println(user);
System.out.println(person);
return "test ok";
}
該註解使用在類上,用於將Model中的數據保存到HttpSession中(跨請求傳遞數據)
屬性名 | 說明 |
---|---|
value | 指定存放到Session域中Model的key的鍵名 |
type | 指定存放到Session域中Model的value的類型 |
@Controller
@SessionAttributes(value={"name"},types = Integer.class)
public class HelloController {
@RequestMapping("/test1")
public String test1(Model model){
System.out.println("--------------test1-----------------");
model.addAttribute("name","zs");
model.addAttribute("age",18);
model.addAttribute("sex","male");
return "redirect:test2";
}
@RequestMapping("/test2")
@ResponseBody
public String test2(ModelMap modelMap, SessionStatus sessionStatus){
System.out.println("--------------test2-----------------");
System.out.println(modelMap.get("name") + " | "+ modelMap.get("age")+ " | "+modelMap.get("sex"));
// 清除Session中保存的數據
sessionStatus.setComplete();
return "test2 ok";
}
}
該註解用於將Session中key對應的value綁定給指定參數
@RequestMapping("/test3")
@ResponseBody
public String test3(@SessionAttribute("name") String name,@SessionAttribute("age") Integer age){
System.out.println("--------------test3-----------------");
System.out.println(name + " | " + age);
return "test3 ok";
}
該註解用於將Request中key對應的value綁定給指定參數
@RequestMapping("/test4")
@ResponseBody
public String test4(@RequestAttribute("sex")String sex){
System.out.println("--------------test4-----------------");
System.out.println(sex);
return "test4 ok";
}
該註解用於綁定請求參數給控制器方法指定參數
// http://localhost:8080/test5?id=1&name=zs
@RequestMapping("/test5")
@ResponseBody
public String test5(@RequestParam("id") Integer id,@RequestParam("name") String username){
System.out.println("--------------test5-----------------");
System.out.println(id + " | " + username);
return "test5 ok";
}
該註解用於將請求頭中參數綁定給控制器指定方法參數
@RequestMapping("/test6")
@ResponseBody
public String test6(@RequestHeader Map requestHeaderMap){
System.out.println("--------------test6-----------------");
requestHeaderMap.forEach((k,v) -> System.out.println(k + " | " +v));
return "test6 ok";
}
注:在上面的案列中,請求頭中所有數據會以key-value的方式存放到Map集合中,也可以使用 @RequestHeader(“Accept-Encoding”) 這樣的方式,獲取特定信息。
該註解用於將Cookie中的value綁定給控制器指定方法參數
@RequestMapping("/test7")
@ResponseBody
public String test7(@CookieValue("JSESSIONID") String jessionId){
System.out.println("--------------test7-----------------");
System.out.println(jessionId);
return "test7 ok";
}
該註解用於將請求主體通過HttpMessageConverter讀取和反序列化爲對象
@PostMapping("/test8")
@ResponseBody
public String test8(@RequestBody User user){
System.out.println(user);
return "test8 ok";
}
該註解用於將方法返回值通過HttpMessageConverter序列化到響應體
該註解用於支持跨越請求處理
@PostMapping("/test10")
@ResponseBody
@CrossOrigin(origins = "http://192.168.31.187:8080",maxAge = 1800)
public String test10(String name,Integer id){
System.out.println(name + " | " + id);
return "test10 ok";
}
瀏覽器從一個域名的網頁去請求另一個域名的資源時,域名、端口、協議任一不同,都是跨域