AOP的概述(7)
阿新 • • 發佈:2018-05-03
AOP什麽是AOP?
- AOP Aspect Oriented Programing 面向切面編程
- AOP采取橫向抽取機制,取代了傳統縱向繼承體系重復性代碼(性能監視、事務管理、安全檢查、緩存)
- Spring AOP使用純Java實現,不需要專門的編譯過程和類加載器,在運行期通過代理方式向目標類織入增強代碼
- AspecJ是一個基於Java語言的AOP框架,Spring2.0開始,Spring AOP引入對Aspect的支持,AspectJ擴展了Java語言,提供了一個專門的編譯器,在編譯時提供橫向代碼的織入
AOP底層原理
就是代理機制:
- 動態代理:(JDK中使用)
- JDK的動態代理,對實現了接口的類生成代理.
Spring的AOP代理
- JDK動態代理:對實現了接口的類生成代理
- CGLib代理機制:對類生成代理
AOP的術語
- Joinpoint(連接點):所謂連接點是指那些被攔截到的點。在spring中,這些點指的是方法,因為spring只支持方法類型的連接點.
- Pointcut(切入點):所謂切入點是指我們要對哪些Joinpoint進行攔截的定義.
- Advice(通知/增強):所謂通知是指攔截到Joinpoint之後所要做的事情就是通知.通知分為前置通知,後置通知,異常通知,最終通知,環繞通知(切面要完成的功能)
- Introduction(引介):引介是一種特殊的通知在不修改類代碼的前提下, Introduction可以在運行期為類動態地添加一些方法或Field.
- Target(目標對象):代理的目標對象
- Weaving(織入):是指把增強應用到目標對象來創建新的代理對象的過程.
- spring采用動態代理織入,而AspectJ采用編譯期織入和類裝在期織入
- Proxy(代理):一個類被AOP織入增強後,就產生一個結果代理類
- Aspect(切面): 是切入點和通知(引介)的結合
解釋以上名詞:
-
joinpoit:連接點,指的是那些方法【可以】被攔截
-
pointcut:切入點,對哪些joinpoint進行攔截
-
advice:通知,指的是 【要 】增強的代碼,(方法級別的增強)
-
introduction:引介,指的是一種特殊方式的advice(類級別的增強,在原有類上添加一個屬性或者方法)
- target:目標對象,唄增強的對象。
- weaving(織入):是指增強(advice)應用到目標對象(targe)來創建新的代理對象的過程。
- proxy:代理對象
- Aspect(切面):是切入點和通知(引介)的結合(允許有多個切點和多個通知的結合)
以下是底層實現demo演示
AOP的底層實現
- JDK動態代理(對實現接口的類進行代理):
接口類:
package cn.spring3.demo1;
/**
* @author NOP
* DAO接口
*/
public interface UserDao {
public void add();
public void update();
}
實現類:
package cn.spring3.demo1;
public class UserDaoImpl implements UserDao {
public void add() {
// TODO Auto-generated method stub
System.out.println("添加用戶");
}
public void update() {
// TODO Auto-generated method stub
System.out.println("修改用戶");
}
}
傳統方式調用:
package cn.spring3.demo1;
import org.junit.Test;
public class SpringTest1 {
@Test
public void demo1() {
UserDao userDao = new UserDaoImpl();
userDao.add();
userDao.update();
}
}
如果增強add方法,怎麽做呢?
方法一:
package cn.spring3.demo1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author NOP JDK動態類裏的機制
* 直接實現Handler,所以JDKProxy自身就是Handler
*/
public class JDKProxy implements InvocationHandler {
private UserDao userDao;
public JDKProxy(UserDao userDao) {
super();
this.userDao = userDao;
}
public UserDao createProxy() {
/**
* invocationHandler兩種方式,一種匿名內部類的方式見JDKProxy1.java
*/
UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass()
.getClassLoader(), userDao.getClass().getInterfaces(), this);
return proxy;
}
//調用目標對象的任何一個方法都相當於調用invoke();
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
if("add".equals(method.getName())){
System.out.println("===日誌記錄===");
Object result = method.invoke(userDao, args);
return result;
}
return method.invoke(userDao, args);
}
}
方法二:
package cn.spring3.demo1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author NOP JDK動態類裏的機制
*/
public class JDKProxy1 {
private UserDao userDao;
public JDKProxy1(UserDao userDao) {
super();
this.userDao = userDao;
}
public UserDao createProxy() {
/**
* invocationHandler兩種方式
*/
UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass()
.getClassLoader(), userDao.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
// TODO Auto-generated method stub
if (method.getName().equals("add")) {
System.out.println("===匿名內部類方式記錄logs日誌====");
Object result = method.invoke(userDao, args);
return result;
}
return method.invoke(userDao, args);
}
});
return proxy;
}
}
編寫測試類
對應JDKProxy.java
@Test
public void demo2() {
//被代理對象
UserDao userDao = new UserDaoImpl();
//創建代理對象的時候傳入被代理對象
UserDao proxy = new JDKProxy(userDao).createProxy();
proxy.add();
proxy.update();
}
測試結果:
===日誌記錄===
添加用戶
修改用戶
對應JDKProxy1.java
@Test
public void demo3() {
UserDao userDao = new UserDaoImpl();
UserDao proxy = new JDKProxy1(userDao).createProxy();
proxy.add();
proxy.update();
}
測試結果:
===匿名內部類方式記錄logs日誌====
添加用戶
修改用戶
AOP的概述(7)