Spring基礎配置----依賴注入&AOP
引言
spring框架本身有四大原則:
- 使用POJO進行輕量級和最小侵入式開發
- 通過依賴注入和基於介面變成實現鬆耦合
- 通過AOP和預設習慣進行宣告式程式設計
- 使用AOP和模板(template)減少模式化程式碼
Spring所有功能的設計和實現都是基於此四大原則。
一、依賴注入
我們將常說的控制反轉(Inversion of Control-IOC)和依賴注入(dependency injection-DI)在Spring環境下是等同的概念,控制反轉是通過依賴注入實現的。所謂的依賴注入是指容器負責建立物件和維護物件間的依賴關係,而不是通過物件本身負責自己的建立和解決自己的依賴。
依賴注入起到的作用就是將物件之間的依賴關係從原先的程式碼中解耦出來,通過配置檔案或註解等方式加上Spring框架的處理讓我們對依賴關係靈活集中的進行管理。依賴注入的主要目的是為了解耦,體現的一種“組合”的概念。如果你希望你的類具備某項功能的時候,是繼承自一個具有此功能的父類好呢?還是組合另外一個具有這個功能的類好?答案是肯定的,如果說你繼承一個父類,子類將於父類耦合,組合另外一個類則是耦合度大大降低。
Spring Ioc 容器(ApplicationContext)負責建立 Bean ,並通過容器將功能類的 bean 注入到你需要的bean 中。Spring 提供使用 xml 、註解、java配置實現 Bean 的建立和注入。
無論是xml配置、註解配置、java配置,都稱之為配置元資料,所謂元資料即描述資料的資料。元資料本身不具備任何執行的能力,只能通過外界的程式碼來對這些元資料解析後進行相應的操作。Spring 容器解析這些配置元資料進行 Bean 初始化、配置和管理依賴。
宣告 Bean 的註解:
- @Component元件,沒有明確的角色
- @Service 在業務邏輯層(service層)使用
- @Repository 在資料訪問層(dao層)使用
- @Controller 在展現層(MVC--->Spring MVC)使用
注入Bean的註解,一般情況下通用
- @Autowired:Spring提供的註解
- @Inject:JSR-330提供的註釋
- @Resource:JSR-250提供的註解
示例
1)編寫功能類的bean。
package com.wsf.spring;
import org.springframework.stereotype.Service;
/**
* @author feng
* @create 2018-09-20 14:00
*/
@Service
public class TestService {
public String sayHello (String world) {
return "Hello " + world ;
}
}
程式碼解釋:
使用@Service 註解聲明當前TestService類是Spring管理的一個類。
2)使用功能類的 Bean。
package com.wsf.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author feng
* @create 2018-09-20 14:04
*/
@Service
public class UseTestService {
@Autowired
TestService testService;
public String sayHello (String word) {
return testService.sayHello(word);
}
}
程式碼解釋:
使用@Service 註解聲明當前UseTestService 類是Spring 管理的一個Bean。
使用@Autowired 將TestService 的實體 Bean注入到 UseTestService 中,讓UseTestService 具備 TestService 的功能。
3)配置類
package com.wsf.spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author feng
* @create 2018-09-20 14:10
*/
@Configuration
@ComponentScan("com.wsf.spring")
public class MyConfig {
}
程式碼解釋:
@Configuration 聲明當前類是一個配置類。
@ComponentScan 自動掃描包名下所有使用@Service、@Component、@Repository和@Controller 的類,並註冊為Bean。
4)執行
import com.wsf.spring.MyConfig;
import com.wsf.spring.UseTestService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author feng
* @create 2018-09-20 14:12
*/
public class MyTest {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(MyConfig.class);
UseTestService useTestService = context.getBean(UseTestService.class);
@Test
public void testSpringIOC(){
System.out.println(useTestService.sayHello("Spring"));
context.close();
}
}
程式碼解釋:
使用AnnotationConfigApplicationContext 作為 Spring 容器 ,接受輸入一個配置類作為引數;
獲得宣告配置的 UseTestService 的Bean。
5)執行結果
Hello Spring
二、AOP
AOP:面向切面程式設計。Spring的AOP的存在是為了解耦。AOP可以讓一組類共享相同的行為。
Spring支援AspectJ的註解式切面程式設計。
1)使用@Aspect宣告是一個切面
2) 使用@After、@Before、@Around 定義建言(advice),可直接將攔截規則(切點)作為引數。
3)其中@After、@Before、@Around引數的攔截規則為切點(PointCut),為了使切點服用,可使用@PointCut專門定義攔截規則,然後再@After、@Before、@Around 的引數中呼叫。
4)其中符合條件的每一個被攔截處為連線點(JoinPoint)。
示例
1)新增Spring aop支援和AspectJ依賴
2)編寫攔截規則的註解。
package com.wsf.spring.aop;
import java.lang.annotation.*;
/**
* @author feng
* @Description:TODO
* @create 2018-09-20 16:36
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Action {
String name();
}
程式碼解釋:
註解本身是沒有功能的,和xml一樣。註解和xml都是一種元資料,元資料即解釋資料的資料,這就是所謂配置。
註解的功能來自用這個註解的地方。
3)編寫使用註解的被攔截類
package com.wsf.spring.aop;
import org.springframework.stereotype.Service;
/**
* @author feng
* @Description:TODO
* @create 2018-09-20 16:38
*/
@Service
public class DemoAnnotationService {
@Action(name="註解式攔截的add操作")
public void add(){}
}
4)編寫使用方法的被攔截類
package com.wsf.spring.aop;
import org.springframework.stereotype.Service;
/**
* @author feng
* @Description:編寫使用方法規則被攔截類
* @create 2018-09-20 16:38
*/
@Service
public class DemoMethodService {
public void add(){}
}
5)編寫切面
package com.wsf.spring.aop;
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;
import java.lang.reflect.Method;
/**
* @author feng
* @Description:TODO
* @create 2018-09-20 16:41
*/
@Aspect
@Component
public class LogAscept {
@Pointcut("@annotation(com.wsf.spring.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.wsf.spring.aop.DemoMethodService.*(..))")
public void before (JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
System.out.println("方法規則式攔截 " + method.getName());
}
}
程式碼解釋:
通過@Aspect註解宣告一個切面。
通過@Component讓此切面成為Spring容器管理的Bean。
通過@PointCut註解宣告切點。
通過@After註解宣告一個建言,並使用@PointCut定義的切點。
通過反射可獲得註解上的屬性,然後做日誌記錄相關的操作。
通過@Before 直接宣告一個建言,此建言直接使用攔截規則作為引數。
6)配置類
package com.wsf.spring.aop;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* @author feng
* @Description:TODO
* @create 2018-09-20 16:54
*/
@Configuration
@ComponentScan("com.wsf.spring.aop")
@EnableAspectJAutoProxy
public class AopConfig {
}
程式碼解釋:使用@EnableAspectJAutoProxy註解開啟Spring對AspectJ代理的支援。
7)執行
import com.wsf.spring.aop.AopConfig;
import com.wsf.spring.aop.DemoAnnotationService;
import com.wsf.spring.aop.DemoMethodService;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author feng
* @create 2018-09-20 14:12
*/
public class AOPTest {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AopConfig.class);
DemoAnnotationService demoAnnotationService = context.getBean(DemoAnnotationService.class);
DemoMethodService demoMethodService = context.getBean(DemoMethodService.class);
/**
* 測試AOP
*/
@Test
public void testSpringAOP(){
demoAnnotationService.add();
demoMethodService.add();
context.close();
}
}
執行結果:
註解式攔截 註解式攔截的add操作 方法規則式攔截 add