面向切面編程(AOP),該種方式主要是為了彌補面向對象編程(OOP)的不足,通過配置切面以及關注點、通知等我們可以在程序的任意位置對我們的代碼進行增強(執行一些代碼),AOP是Spring的特性之一,通常我們使用AOP來實現日志的補記錄以及實現一些聲明式的事務等。
接下來,通過一個簡單的例子來測試一下AOP如何使用:
1、pom.xml文件的依賴如下
<dependencies> <!--1.單元測試的依賴--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--2.aop的依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!--3.cglib動態代理的依賴--> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency> <!--4.web依賴--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--5.小辣椒--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies>
2、application.yml(springboot)的配置文件內容如下:
其中,server.port代表端口號(tomcat的端口號)
其他內容為自定義的內容,可通過@Value注解獲取到內容值
${name}為使用表達式獲取當前yml文件中對應的name的值
3、定義用於返回的類(使用RestController,返回json數據),代碼如下:
@Data @NoArgsConstructor @AllArgsConstructor public class Result { private boolean success; private String msg; }
4、定義自己的Service類(模擬業務場景),代碼如下:
@Service public class JieService { public void todo(){ System.out.println("這是一個Service方法的調用!"); } }
@Service :把該類注入Spring容器中,若需要使用,則通過@Autowired 注解獲取
5、定義一個Controller類(控制類,模擬處理用戶的請求),代碼如下:
@RestController public class JieController { @Autowired private JieService jieService; // 使用yml配置文件中的參數 @Value("${content}") public String content; @RequestMapping("/hello") public Result hello(){ jieService.todo(); return new Result(true,content); } }
其中,@Autowired 注解則獲取到Spring容器中我們通過@Service 注解注入的對象
@RestController 注解為標記返回的數據為json格式
@Value 注解則獲取到application.yml 文件中對應的參數名的值,這里@Value(${content})的寫法跟在yml中去到定義的值一樣
6、配置一個切面類,且注入Spring容器中,通過@Aspect 標記為切面類、@Component 注入Spring容器中,並且添加一些測試方法,代碼如下:
@Component // 注冊到spring容器中 @Aspect // 標志為切面類 public class ServiceAdvice { /** * 解讀: * execution為固定寫法 * public * com.jieku.service..*.*(..) * 第一個 * 表示所有的返回參數 * 之后代表切入點的包名,其后跟着兩個點(.)表示當前包及其所有的子包 * 兩個點后的* 代表所有的類 =》 綜合兩個點加上* ..* 表示當前包及其所有子包的所有類 * 之后的點個人理解為調用方法,點后的*表示所有的方法,之后括號中的兩個點.表示任意的參數個數 * 總的解答:攔截com.jieku.service的當前包及其子包中的所有類(任意的返回參數類型)的所有方法的調用(任意參數列表) */ @Pointcut("execution(public * com.jieku.service..*.*(..))") public void good(){} @Before("good()") public void before(){ System.out.println("之前攔截到了,並且執行了!"); } @After("good()") public void after(){ System.out.println("之后也攔截到了,並且執行了!"); } /** * @Ponitcut:表示切入點,理解為找到需要增強的方法執行我們定義的增強的代碼 * 通知: * @Before:前置通知,方法執行前執行該通知 * @After:后置通知,方法執行完成之后執行該通知 * @Around:環繞通知 * @AfterReturning:在返回之后執行該通知 * @AfterThrowing:在拋出異常后執行該通知 */ }
7、執行效果如下:
在頁面上輸入:localhost:8080/hello,執行效果如下:
8、補充:啟動類以及項目結構圖
啟動類代碼如下:
@SpringBootApplication public class JieApplication { public static void main(String[] args) { SpringApplication.run(JieApplication.class); } }
項目結構圖如下:
9、后台的運行結果:
至此,簡單測試成功!