Spring Boot實戰(1) Spring基礎
1. Spring基礎配置
Spring框架本身有四大原則:
1) 使用POJO進行輕量級和最小侵入式開發
2) 通過依賴註入和基於接口編程實現松耦合
3) 通過AOP和默認習慣進行聲明式編程
4) 使用AOP和模板(template)減少模式化代碼
所謂依賴註入指的是容器負責創建對象和維護對象間的依賴關系,而不是通過對象本身負責自己的創建和解決自己的依賴。依賴註入主要目的是為了解耦。
Spring Ioc容器(ApplicationContext)負責創建Bean,並通過容器將功能類Bean註入到你需要的Bean中。
聲明Bean的註解:
a. @Component組件
b. @Service在業務邏輯層(Service層)使用
c. @Repository在數據訪問層(dao層)使用
e. @Controller在展現層使用
註入Bean的註解,一般情況下是通用的:
a. @Autowired:Spring提供的註解
b. @Resourse: JSR-250提供的註解
c. @Inject: JSR-330提供的註解
示例:
1) 構件maven項目,其pom.xml配置文件如下:
1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsdView Code"> 3 <modelVersion>4.0.0</modelVersion> 4 5 <groupId>com.ws</groupId> 6 <artifactId>study1</artifactId> 7 <version>0.0.1-SNAPSHOT</version> 8 <packaging>jar</packaging> 9 10 <name>study1</name> 11 <url>http://maven.apache.org</url>12 13 <properties> 14 <java.version>1.7</java.version> 15 <spring-framework.version>4.1.5.RELEASE</spring-framework.version> 16 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 17 </properties> 18 19 20 <dependencies> 21 <dependency> 22 <groupId>junit</groupId> 23 <artifactId>junit</artifactId> 24 <version>3.8.1</version> 25 <scope>test</scope> 26 </dependency> 27 <dependency> 28 <groupId>org.springframework</groupId> 29 <artifactId>spring-context</artifactId> 30 <version>${spring-framework.version}</version> 31 </dependency> 32 </dependencies> 33 </project> 34
2) 編寫功能類Bean
1 package com.ws.study.one; 2 3 import org.springframework.stereotype.Service; 4 5 // @Service註解聲明當前FunctionService類是Spring管理的一個Bean 6 @Service 7 public class FunctionService { 8 public String sayHello(String word){ 9 return "Hello " + word + " !"; 10 } 11 }View Code
3) 使用編寫好的功能類Bean
1 package com.ws.study.one; 2 3 import org.springframework.beans.factory.annotation.Autowired; 4 import org.springframework.stereotype.Service; 5 6 // @Service註解聲明當前類是Spring管理的一個Bean 7 @Service 8 public class UseFunctionService { 9 10 // @Autowired實體將FunctionService的實體Bean註入到UseFunctionService中, 11 // 進而使UseFunctionService具備FunctionService的功能 12 @Autowired 13 FunctionService functionService; 14 15 public String sayHello(String word){ 16 return functionService.sayHello(word); 17 } 18 } 19View Code
4) 配置類
1 package com.ws.study.one; 2 3 import org.springframework.context.annotation.ComponentScan; 4 import org.springframework.stereotype.Component; 5 6 // @Component聲明當前類是一個配置類 7 @Component 8 // 使用@ComponentScan,自動掃描包下所有使用@Service、@Component、@Repository和@Controller的類,並註冊為Bean 9 @ComponentScan("com.ws.study.one") 10 public class DiConfig { 11 12 } 13View Code
5) 運行類
1 package com.ws.study.one; 2 3 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 5 public class Main { 6 public static void main(String[] args) { 7 // 使用AnnotationConfigApplicationContext作為Spring容器,接受輸入一個配置類作為參數 8 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DiConfig.class); 9 10 // 獲取聲明配置的UseFunctionService的Bean 11 UseFunctionService useFunctionService = context.getBean(UseFunctionService.class); 12 13 System.out.println(useFunctionService.sayHello("di")); 14 15 context.close(); 16 } 17 } 18View Code
6) 運行結果
1 五月 29, 2018 11:07:20 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh 2 信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1fc0f2f: startup date [Tue May 29 23:07:20 CST 2018]; root of context hierarchy 3 Hello di ! 4 五月 29, 2018 11:07:20 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 5 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1fc0f2f: startup date [Tue May 29 23:07:20 CST 2018]; root of context hierarchy 6View Code
2. Java配置
java配置可以完全替代xml配置,也是Spring Boot推薦的配置方式。java配置是通過@Configuration和@Bean來實現的。
a. @Configuration聲明當前類是一個配置類,相當於一個Spring配置的xml文件
b. @Bean註解在方法上,聲明當前方法的返回值是一個Bean
何時使用java配置或註解配置?原則:全局配置使用java配置(如數據庫配置、MVC相關配置),業務Bean的配置使用註解配置(@Service、@Component、@Repository、@Controller)
示例:
1) 編寫功能類
1 package com.ws.study.javaconfig; 2 3 // 此處沒有@Service聲明的Bean 4 public class FunctionService { 5 public String sayHello(String word){ 6 return "Hello " + word + " !"; 7 } 8 } 9View Code
2) 使用功能類
1 package com.ws.study.javaconfig; 2 3 //此處沒有@Service聲明的Bean 4 public class UseFunctionService { 5 // 此處沒有@Autowired聲明的Bean 6 FunctionService functionService; 7 8 public void setFunctionService(FunctionService functionService) { 9 this.functionService = functionService; 10 } 11 12 public String sayHello(String word){ 13 return functionService.sayHello(word); 14 } 15 } 16View Code
3) 配置類
1 package com.ws.study.javaconfig; 2 3 import org.springframework.context.annotation.Bean; 4 import org.springframework.context.annotation.Configuration; 5 6 // 使用@Configuration註解聲明當前類是一個配置類。意味著這個類中可能存在0個或多個@Bean註解 7 // 此處沒有使用包掃描,是因為所有的Bean都在此類中定義了 8 @Configuration 9 public class JavaConfig { 10 11 // 使用@Bean註解聲明當前方法FunctionService的返回值是一個Bean,Bean的名稱是方法名 12 @Bean 13 public FunctionService functionService(){ 14 return new FunctionService(); 15 } 16 17 @Bean 18 public UseFunctionService useFunctionService(){ 19 UseFunctionService useFunctionService = new UseFunctionService(); 20 // 註入FunctionService的Bean時候直接調用functionService() 21 useFunctionService.setFunctionService(functionService()); 22 return useFunctionService; 23 } 24 25 // // 另外一種註解方式,直接將FunctionService作為參數給useFunctionService() 26 // // 在Spring容器中,只要容器中存在某個Bean,就可以在另外一個Bean的聲明方法的參數中寫入 27 // @Bean 28 // public UseFunctionService useFunctionService(FunctionService functionService){ 29 // UseFunctionService useFunctionService = new UseFunctionService(); 30 // useFunctionService.setFunctionService(functionService); 31 // return useFunctionService; 32 // } 33 } 34View Code
4) 運行類
1 package com.ws.study.javaconfig; 2 3 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 5 public class Main { 6 public static void main(String[] args) { 7 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(JavaConfig.class); 8 9 UseFunctionService useFunctionService = context.getBean(UseFunctionService.class); 10 11 System.out.println(useFunctionService.sayHello("java config")); 12 13 context.close(); 14 } 15 } 16View Code
5) 運行結果
1 五月 29, 2018 11:36:47 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh 2 信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1fc0f2f: startup date [Tue May 29 23:36:47 CST 2018]; root of context hierarchy 3 Hello java config ! 4 五月 29, 2018 11:36:47 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 5 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1fc0f2f: startup date [Tue May 29 23:36:47 CST 2018]; root of context hierarchy 6View Code
3. AOP
AOP為面向切面編程,切面編程是指在程序運行期間將某段代碼,動態的切入到某個類的指定方法的指定位置。AOP存在的目的是為了解耦。AOP可以讓一組類共享相同的行為。Spring支持AspectJ的註解式切面編程。
a. 使用@AspectJ聲明是一個切面
b. 使用@After、@Before、@Around定義建言(advice),可直接將攔截規則(切點)作為參數。為了使攔截規則(切點)復用,可使用@PointCut專門定義攔截規則,然後在@After、@Before、@Around的參數中調用。
c. 其中符合條件的每一個被攔截處為連接點(JoinPoint)
Spring本身在事務處理(@Transcational)和數據緩存(@Cacheable)上面都使用註解式攔截。
示例:
1) 添加spring aop支持及AspectJ依賴
1 <!-- spring aop支持 --> 2 <dependency> 3 <groupId>org.springframework</groupId> 4 <artifactId>spring-aop</artifactId> 5 <version>${spring-framework.version}</version> 6 </dependency> 7 <!-- aspectj支持 --> 8 <dependency> 9 <groupId>org.aspectj</groupId> 10 <artifactId>aspectjrt</artifactId> 11 <version>1.8.6</version> 12 </dependency> 13 <dependency> 14 <groupId>org.aspectj</groupId> 15 <artifactId>aspectjweaver</artifactId> 16 <version>1.8.5</version> 17 </dependency>View Code
2) 編寫攔截規則的註解
1 package com.ws.study.aop; 2 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 8 // 註解本身沒有功能 9 // 註解和XML都是元數據 10 // 註解的功能來自用這個註解的地方 11 @Target(ElementType.METHOD) 12 @Retention(RetentionPolicy.RUNTIME) 13 public @interface Action { 14 } 15View Code
3) 編寫使用註解的被攔截類
1 package com.ws.study.aop; 2 3 import org.springframework.stereotype.Service; 4 5 @Service 6 public class DemoAnnotationService { 7 @Action(name = "註解式攔截的add操作") 8 public void add(){} 9 } 10View Code
4) 編寫使用方法規則被攔截類
1 package com.ws.study.aop; 2 3 import org.springframework.stereotype.Service; 4 5 @Service 6 public class DemoMethodService { 7 public void add(){} 8 } 9View Code
5) 編寫切面
1 package com.ws.study.aop; 2 3 import java.lang.reflect.Method; 4 5 import org.aspectj.lang.JoinPoint; 6 import org.aspectj.lang.annotation.After; 7 import org.aspectj.lang.annotation.Aspect; 8 import org.aspectj.lang.annotation.Before; 9 import org.aspectj.lang.annotation.Pointcut; 10 import org.aspectj.lang.reflect.MethodSignature; 11 import org.springframework.stereotype.Component; 12 13 // @Aspect註解聲明一個切面 14 @Aspect 15 // @Component讓此切面成為Spring容器管理的Bean 16 @Component 17 public class LogAspect { 18 19 // @Pointcut註解聲明切點 20 @Pointcut("@annotation(com.ws.study.aop.Action)") 21 public void annotationPointCut(){}; 22 23 // 通過@After註解聲明一個建言,並使用@PointCut定義的切點 24 @After("annotationPointCut()") 25 public void after(JoinPoint joinpoint){ 26 MethodSignature signature = (MethodSignature) joinpoint.getSignature(); 27 Method method = signature.getMethod(); 28 Action action = method.getAnnotation(Action.class); 29 // 通過反射可獲取註解上的屬性,然後做日誌記錄相關的操作 30 System.out.println("註解式攔截:"+action.name()); 31 } 32 33 // 通過@Before註解聲明一個建言,此建言直接使用攔截規則作為參數 34 @Before("execution(* com.ws.study.aop.DemoMethodService.*(..))") 35 public void before(JoinPoint joinPoint){ 36 MethodSignature signature = (MethodSignature)joinPoint.getSignature(); 37 Method method = signature.getMethod(); 38 System.out.println("方法規則式攔截: "+method.getName()); 39 } 40 } 41View Code
6) 配置類
1 package com.ws.study.aop; 2 3 import org.springframework.context.annotation.ComponentScan; 4 import org.springframework.context.annotation.Configuration; 5 import org.springframework.context.annotation.EnableAspectJAutoProxy; 6 7 @Configuration 8 @ComponentScan("com.ws.study.aop") 9 // 使用@EnableAspectJAutoProxy註解開啟Spring對AspectJ代理的支持 10 @EnableAspectJAutoProxy 11 public class AopConfig { 12 13 } 14View Code
7) 運行類
1 package com.ws.study.aop; 2 3 import org.springframework.context.annotation.AnnotationConfigApplicationContext; 4 5 public class Main { 6 7 public static void main(String[] args) { 8 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopConfig.class); 9 10 DemoAnnotationService demoAnnotationService = context.getBean(DemoAnnotationService.class); 11 demoAnnotationService.add(); 12 13 DemoMethodService demoMethodService = context.getBean(DemoMethodService.class); 14 demoMethodService.add(); 15 16 context.close(); 17 } 18 19 } 20View Code
8) 運行結果
1 五月 30, 2018 10:06:14 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh 2 信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1531931: startup date [Wed May 30 22:06:14 CST 2018]; root of context hierarchy 3 註解式攔截:註解式攔截的add操作 4 方法規則式攔截: add 5 五月 30, 2018 10:12:09 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext doClose 6 信息: Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1531931: startup date [Wed May 30 22:06:14 CST 2018]; root of context hierarchy 7View Code
Spring Boot實戰(1) Spring基礎