概述:
Aop, aspect object programming 面向切面編程
功能: 讓關注點代碼與業務代碼分離!
關注點,
重複代碼就叫做關注點;
切面,
關注點形成的類,就叫切面(類)!
面向切面編程,就是指 對很多功能都有的重複的代碼抽取,再在運行的時候往業務方法上動態植入“切面類代碼”。
切入點,
執行目標對象方法,動態植入切面代碼。
可以通過切入點表達式,指定攔截哪些類的哪些方法; 給指定的類在運行的時候植入切面類代碼。
3.2 註解方式實現AOP編程
步驟:
1) 先引入aop相關jar文件 (aspectj aop優秀組件)
spring-aop-3.2.5.RELEASE.jar 【spring3.2源碼】
aopalliance.jar 【spring2.5源碼/lib/aopalliance】
aspectjweaver.jar 【spring2.5源碼/lib/aspectj】或【aspectj-1.8.2\lib】
aspectjrt.jar 【spring2.5源碼/lib/aspectj】或【aspectj-1.8.2\lib】
注意: 用到spring2.5版本的jar文件,如果用jdk1.7可能會有問題。
需要升級aspectj組件,即使用aspectj-1.8.2版本中提供jar文件提供。
2) bean.xml中引入aop名稱空間
3) 開啓aop註解
4) 使用註解
@Aspect 指定一個類爲切面類
@Pointcut("execution(* cn.itcast.e_aop_anno.*.*(..))") 指定切入點表達式
@Before("pointCut_()") 前置通知: 目標方法之前執行
@After("pointCut_()") 後置通知:目標方法之後執行(始終執行)
@AfterReturning("pointCut_()") 返回後通知: 執行方法結束前執行(異常不執行)
@AfterThrowing("pointCut_()") 異常通知: 出現異常時候執行
@Around("pointCut_()") 環繞通知: 環繞目標方法執行
package com.anno;
public interface IUserDao {
void save();
}
package com.anno;
import org.springframework.stereotype.Component;
@Component //加入容器
public class UserDao implements IUserDao{
@Override
public void save() {
System.out.println("-----核心業務,保存!------");
}
}
package com.anno;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component//加入容器
@Scope("prototype")
public class OrderDao{
public void save() {
System.out.println("------核心業務,保存!------");
}
}
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 開啓註解掃描 -->
<context:component-scan base-package="com.anno"></context:component-scan>
<!-- 開啓aop註解方式 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
package com.anno;
/**
* @version v1.0
* @Package com.com.anno
* @auther LaurenceLau
* @date 2020/6/16,9:57
* @description
*/
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect // 指定當前類爲切面類
public class Aop {
// 指定切入點表單式: 攔截哪些方法; 即爲哪些類生成代理對象
@Pointcut("execution(* com.anno.*.*(..))")//在這個包下的所有方法執行目標對像的方法的時候自動創建代理對象
public void pointCut_(){
}
// 前置通知 : 在執行目標方法之前執行
@Before("pointCut_()")
public void begin(){
System.out.println("開始事務/異常");
}
// 後置/最終通知:在執行目標方法之後執行 【無論是否出現異常最終都會執行】
@After("pointCut_()")
public void after(){
System.out.println("提交事務/關閉");
}
// 返回後通知: 在調用目標方法結束後執行 【出現異常不執行】
@AfterReturning("pointCut_()")
public void afterReturning() {
System.out.println("afterReturning()");
}
// 異常通知: 當目標方法執行異常時候執行此關注點代碼
@AfterThrowing("pointCut_()")
public void afterThrowing(){
System.out.println("afterThrowing()");
}
// 環繞通知:環繞目標方式執行
@Around("pointCut_()")
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("環繞前....");
pjp.proceed(); // 執行目標方法
System.out.println("環繞後....");
}
}
package com.anno;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
ApplicationContext ac =
new ClassPathXmlApplicationContext("com/anno/bean.xml");
// 目標對象有實現接口,spring會自動選擇“JDK代理”
@Test
public void testApp() {
IUserDao userDao = (IUserDao) ac.getBean("userDao");
System.out.println(userDao.getClass());//$Proxy001
userDao.save();
}
// 目標對象沒有實現接口, spring會用“cglib代理”
@Test
public void testCglib() {
OrderDao orderDao = (OrderDao) ac.getBean("orderDao");
System.out.println(orderDao.getClass());
orderDao.save();
}
@Deprecated
// 共性問題:如果目標對象有實現接口,在從容器中獲取目標對象的時候,只能通過接口接收對象。
public void testApp2() {
// 錯誤代碼: 只能用接口接收
UserDao userDao = (UserDao) ac.getBean("userDao");
System.out.println(userDao.getClass());//$Proxy001
userDao.save();
}
@Test
public void testGetObj() throws Exception {
OrderDao orderDao1 = (OrderDao) ac.getBean("orderDao");
OrderDao orderDao2 = (OrderDao) ac.getBean("orderDao");
System.out.println(orderDao1);
System.out.println(orderDao2);
}
}