Spring基礎(3)--- Spring基礎配置
Spring 基礎配置
Sprin框架本身有四大原則:
- 使用POJO進行輕量級和最小侵入式開發。
- 通過依賴註入和基於接口編程實現松耦合。
- 通過AOP實現默認習慣進行聲明式編程。
- 使用AOP和模板(template)減少模塊化代碼。
Spring 所有的功能的設計和實現都是基於此四大原則的。
1、依賴註入
1.1、理論
我們經常說的控制反轉(IOC)和依賴註入(DI)在Spring環境下是兩個等同的概念,控制反轉是通過依賴註入實現的。所謂依賴註入是指容器在負責創建對象和維護對象間的依賴關系,而不是通過對象本身負責自己的創建和解決自己的依賴。
依賴註入的主要目的是為了解耦,體現了一種“組合”的理念。如果你希望你的類具備一個類的功能如果繼承一個父類,子類和父類將耦合,如果組合另外一個類則使耦合度降低。
Spring IOC容器負責創建Bean,並將功能類的Bean註入到你需要的Bean中,Spring可以通過XML配置,註解還有JAVA配置來實現Bean的創建和出入,無能是那種配置,這些配置都被稱之為配置元數據,也叫描述數據,意思就是這個數據本身不具備任何執行能力,只能通過外界代碼來對這些元數據進行解析後進行一些有意思的數據。
聲明Bean的註解:
- @Component 組件,沒有明確的角色。
- @Controller 在展現層(MVC→SpringMVC)使用。
- @Service 在業務邏輯層(service層)使用。
@Repository 在數據訪問層(dao層)使用。
註入Bean的註解,一般情況下通用
- @Autowired:Spring提供的註解。
- @Inject:JSR-330提供的註解。
@Resource:JSR-250提供的註解。
1.2、示例
1)編寫功能類的Bean。
package com.wisely.highlight_spring4.ch1.di; import org.springframework.stereotype.Service; @Service //使用@Service註解聲明當前FunctionService類是Spring管理的一個Bean。其中,使用@Controller、@Service、@Repository和@Controller是等效的,可根據當前Bean在哪一層使用。 public class FunctionService { public String sayHello(String word){ return "Hello " + word +" !"; } }
2)使用功能類的Bean。
package com.wisely.highlight_spring4.ch1.di; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service //聲明當前類是Spring管理的一個Bean public class UseFunctionService { @Autowired //將FunctionService的實體Bean註入到UseFunctionService中 FunctionService functionService; public String SayHello(String word){ return functionService.sayHello(word); } }
3)配置類
package com.wisely.highlight_spring4.ch1.di;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration //聲明當前類是一個配置類
@ComponentScan("com.wisely.highlight_spring4.ch1.di") //自動掃描包名下所有的@Service、@Component、@Repository、@Controller的類並註冊為Bean
public class DiConfig {
}
4)運行
package com.wisely.highlight_spring4.ch1.di;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
//使用AnnotationConfigApplicationContext作為容器,接受一個配置類作為參數拿到上下文對象
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(DiConfig.class);
//獲得Bean
UseFunctionService useFunctionService = context.getBean(UseFunctionService.class);
System.out.println(useFunctionService.SayHello("world"));//Hello world !
context.close();
}
}
2、Java配置
2.1、理論
Java配置是Spring4.x推薦的配置方式,可以完全取代xml配置;Java配置也是SpringBoot推薦的配置方式。
Java配置主要是通過@Configuration和@Bean來實現的。
- @Configuration聲明當前類是一個配置類,相當於一個Spring裏面配置的xml文件。
- @Bean註解在方法上,聲明當前方法的返回值是一個Bean。
如果用Java配置替代xml配置的話,那我們主要的原則是:全局配置用Java配置(如數據庫相關配置、MVC相關配置),業務Bean的配置使用的是註解配置(@Service、@Component、@Repository、@Controller).
2.2、示例
1)編寫功能類的Bean
package com.wisely.highlight_spring4.ch1.javaconfig;
//這裏沒有用@Service註解聲明Bean
public class FunctionService {
public String sayHello(String word){
return "Hello " + word +" !";
}
}
2)使用功能類的Bean
package com.wisely.highlight_spring4.ch1.javaconfig;
//此處沒有用@Service聲明Bean
public class UseFunctionService {
//此處也沒有用@AutoWired註解註入
FunctionService functionService;
public void setFunctionService(FunctionService functionService) {
this.functionService = functionService;
}
public String SayHello(String word){
return functionService.sayHello(word);
}
}
3)配置類
package com.wisely.highlight_spring4.ch1.javaconfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration //聲明這是一個配置類,這意味著這個類裏面有0個或者多個@Bean註解,此處沒有用@ComponentScan包掃描註解
public class JavaConfig {
@Bean //聲明當前方法返回的是一個Bean,Bean的名稱是方法名
public FunctionService functionService(){
return new FunctionService();
}
@Bean
public UseFunctionService useFunctionService(){
UseFunctionService useFunctionService = new UseFunctionService();
useFunctionService.setFunctionService(functionService()); //註入FunctionService的Bean時候直接調用functionService()。
return useFunctionService;
}
// @Bean
//另外一種註入方式:直接將FunctionService作為參數給useFunctionService(),這也是Spring容器中,只要容器中存在這個Bean,就可以在
//另外一個Bean的聲明方法中作為參數註入。
// public UseFunctionService useFunctionService(FunctionService functionService){//4
// UseFunctionService useFunctionService = new UseFunctionService();
// useFunctionService.setFunctionService(functionService);
// return useFunctionService;
// }
}
4)運行
package com.wisely.highlight_spring4.ch1.javaconfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(JavaConfig.class);
UseFunctionService useFunctionService = context.getBean(UseFunctionService.class);
System.out.println(useFunctionService.SayHello("java config"));//Hello java config!
context.close();
}
}
3、AOP
3.1、理論
AOP:面向切面編程,相對於OOP面向對象編程。
Spring的AOP的存在主要是為了解耦。AOP可以讓一組類共享共同的行為,在OOP中只能用集成類或者實現接口來實現,這樣會是代碼的耦合性增強,並且集成只能單繼承,阻礙更多的行為添加在一組類上,AOP主要是為了彌補OOP的不足。
Spring支持AspectJ的註解式切面編程。
- 使用@Asopect聲明一個切面。
- 使用@After、@Before、@Around定義建言(advice),可以直接將攔截規則(切點)作為參數。
- 其中@After、@Before、@Around參數的攔截規則為切點(PonintCut),為了使切點復用,可以用@PonitCut專門定義攔截規則,然後在@After、@Before、@Around的參數中調用。
4.其中符合條件的每一個被攔截處被稱為連接點(JoinPonit)。
3.2、示例
1)pom.xml中添加spring aop支持以及AspectJ依賴
<!-- spring aop支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring-framework.version}</version>
</dependency>
<!-- aspectj支持 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.5</version>
</dependency>
2)編寫攔截規則註解(自定義一個註解)
package com.wisely.highlight_spring4.ch1.aop;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//@Target說明了Annotation所修飾的對象範圍:Annotation可被用於 packages、types(類、接口、枚舉、Annotation類型)、類型成員(方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
// 作用:用於描述註解的使用範圍(即:被描述的註解可以用在什麽地方)
// 取值(ElementType)有:
// 1.CONSTRUCTOR:用於描述構造器
// 2.FIELD:用於描述域
// 3.LOCAL_VARIABLE:用於描述局部變量
// 4.METHOD:用於描述方法
// 5.PACKAGE:用於描述包
// 6.PARAMETER:用於描述參數
// 7.TYPE:用於描述類、接口(包括註解類型) 或enum聲明
//@Retention定義了該Annotation被保留的時間長短:某些Annotation僅出現在源代碼中,而被編譯器丟棄;而另一些卻被編譯在class文件中;編譯在class文件中的Annotation可能會被虛擬機忽略,而另一些在class被裝載時將被讀取(請註意並不影響class的執行,因為Annotation與class在使用上是被分離的)。使用這個meta-Annotation可以對 Annotation的“生命周期”限制。
// 作用:表示需要在什麽級別保存該註釋信息,用於描述註解的生命周期(即:被描述的註解在什麽範圍內有效)
// 取值(RetentionPoicy)有:
// 1.SOURCE:在源文件中有效(即源文件保留)
// 2.CLASS:在class文件中有效(即class保留)
// 3.RUNTIME:在運行時有效(即運行時保留)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {
String name();
}
3)編寫使用註解的被攔截類
package com.wisely.highlight_spring4.ch1.aop;
import org.springframework.stereotype.Service;
@Service
public class DemoAnnotationService {
@Action(name="註解式攔截的add操作")
public void add(){}
}
4)編寫使用方法規則被攔截的類
package com.wisely.highlight_spring4.ch1.aop;
import org.springframework.stereotype.Service;
@Service
public class DemoMethodService {
public void add(){}
}
5)編寫切面
package com.wisely.highlight_spring4.ch1.aop;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
@Aspect //聲明一個切面
@Component //讓此切面成為Spring容器管理的Bean
public class LogAspect {
@Pointcut("@annotation(com.wisely.highlight_spring4.ch1.aop.Action)") //聲明切點
public void annotationPointCut(){};
@After("annotationPointCut()") //後置通知
public void after(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
Action action = method.getAnnotation(Action.class);
System.out.println("註解式攔截 " + action.name()); //利用反射獲得註解上的屬性,然後可以做日誌相關的操作
}
@Before("execution(* com.wisely.highlight_spring4.ch1.aop.DemoMethodService.*(..))") //前置通知
public void before(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("方法規則式攔截,"+method.getName());
}
}
6)配置類
package com.wisely.highlight_spring4.ch1.aop;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.wisely.highlight_spring4.ch1.aop")
@EnableAspectJAutoProxy //開啟Spring對AspectJ支持
public class AopConfig {
}
7)運行
package com.wisely.highlight_spring4.ch1.aop;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AopConfig.class);
DemoAnnotationService demoAnnotationService = context.getBean(DemoAnnotationService.class);
DemoMethodService demoMethodService = context.getBean(DemoMethodService.class);
demoAnnotationService.add();
demoMethodService.add();
context.close();
}
}
Spring基礎(3)--- Spring基礎配置