Spring AOP 原理 理解
代理模式: 就好比明星和經紀人,經紀人負責接活,負責明星唱歌前會場準備,明星唱歌后收錢。 代理類其實就是在代理對象,前後做了一些其他的處理, 這已經具備 AOP的輪廓了
// 接口
public interface IUserDao {
void save();
void find();
}
// 目標對象
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("模擬:保存用戶!");
}
@Override
public void find() {
System.out.println("模擬:查詢用戶");
}
}
/**
* 靜態代理 特點:
* 1. 目標對象必須要實現接口
* 2. 代理對象,要實現與目標對象一樣的接口
*/
public class UserDaoProxy implements IUserDao {
// 代理對象,需要維護一個目標對象
private IUserDao target = new UserDao();
@Override
public void save() {
System.out.println("代理操作: 開啓事務...");
target.save(); // 執行目標對象的方法
System.out.println("代理操作:提交事務...");
}
@Override
public void find() {
target.find();
}
}
public class StaticProxyTest {
/**
* @param args
*/
public static void main(String[] args) {
IUserDao proxy = new UserDaoProxy();
proxy.save();
}
}
可以看到,靜態代理是必須要有接口的,代理類和目標類都得事先接口,這樣就顯得很麻煩了,每次代理一個目標對象,就得做一個代理類,有沒有一種方式,可以使用一個代理 ,代理多個目標對象呢?
於是就有了動態代理:
動態代理不需要提前建立代理,而是在運行時,爲目標對象動態生成代理類
// 接口
public interface IUserDao {
void save();
void find();
}
// 目標對象
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("模擬: 保存用戶!");
}
@Override
public void find() {
System.out.println("查詢");
}
}
/**
* 動態代理:JDK 動態代理採用的是反射機制實現
* 代理工廠,給多個目標對象生成代理對象!
*
*/
public class ProxyFactory {
// 接收一個目標對象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
// 返回對目標對象(target)代理後的對象(proxy)
public Object getProxyInstance() {
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目標對象使用的類加載器
target.getClass().getInterfaces(), // 目標對象實現的所有接口
new InvocationHandler() { // 執行代理對象方法時候觸發
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 獲取當前執行的方法的方法名
String methodName = method.getName();
// 方法返回值
Object result = null;
if ("find".equals(methodName)) {
// 直接調用目標對象方法
result = method.invoke(target, args);
} else {
System.out.println("開啓事務...");
// 執行目標對象方法
result = method.invoke(target, args);
System.out.println("提交事務...");
}
return result;
}
}
);
return proxy;
}
}
public class JDKDynamicProxyTest {
/**
* @param args
*/
public static void main(String[] args) {
// 目標對象
IUserDao target = new UserDao();
// 創建代理類
IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
System.out.println("代理對象: "+proxy.getClass());
proxy.save();
}
}
可以總結一下,JDK 動態代理
// 創建代理類
IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
實際上 隱藏了動態的去實現 目標對象的一個接口
class $jdkProxy implements IUserDao{}
也就是說 使用JDK 反射方式實現動態代理,目標對象必須實現一個接口,這就可能出現問題了,假設一個類,就是沒有實現接口怎麼辦?
因此就有了使用CGLIB實現動態代理
CGLIB是使用繼承的方式動態生成代理類,這個代理類是繼承目標類的,這個就有個問題,需要目標類不被final修飾。
有點類似
public class UserDao{}
// CGLIB 是以動態生成的子類繼承目標的方式實現,程序執行時,隱藏了下面的過程
public class $Cglib_Proxy_class extends UserDao{}
CGLIB實現
// 目標對象
public class UserDao {
public void save() {
System.out.println("模擬: 保存用戶!");
}
public void find() {
System.out.println("查詢");
}
}
public class CGLIBProxyFactory {
static class SimpleInterceptor implements MethodInterceptor {
/**
* @see org.springframework.cglib.proxy.MethodInterceptor#intercept(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[],
* org.springframework.cglib.proxy.MethodProxy)
*/
@Override
public Object intercept(Object target, Method methmod, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("entering " + methmod.getName());
Object result = proxy.invokeSuper(target, args);
System.out.println("leveaing " + methmod.getName());
return result;
}
}
public static <T> T getProxy(Class<T> cls) {
Enhancer enhancer = new Enhancer();
// 繼承目標類
enhancer.setSuperclass(cls);
enhancer.setCallback(new SimpleInterceptor());
return (T) enhancer.create();
}
}
public class CGLIBProxyTest {
public static void main(String[] args) {
//生成代理 沒有接口
UserDao proxy = (UserDao) CGLIBProxyFactory.getProxy(UserDao.class);
System.out.println("代理類:"+ proxy.getClass());
proxy.save();
}
}
JDK和CGLIB的區別
1.上面可以可以看到 CGLIB是不需要 目標對象實現接口的, CGLIB是通過繼承來實現的
2. JDK動態代理是需要一個具體的目標對象的,但是CGLIB是不需要這麼一個具體對象的
Spring AOP 是怎樣實現的呢?
1.AOP 是基於動態代理模式
2.AOP是方法級別的
3.AOP可以分類業務代碼和關注點代碼(日誌,事務等)
AOP 是什麼時候生成代理的?
AOP 代理主要分爲靜態代理和動態代理兩大類,靜態代理以 AspectJ 爲代表;而動態代理則以 Spring AOP 爲代表
IOC容器BeanDefinitionMap裏面結構看內容是啥
bean: class [org.springframework.aop.aspectj.AspectJPointcutAdvisor];
scope=;
abstract=false;
lazyInit=false;
autowireMode=0;
dependencyCheck=0;
autowireCandidate=true;
primary=false;
factoryBeanName=null;
factoryMethodName=null;
initMethodName=null;
destroyMethodName=null,
org.springframework.aop.aspectj.AspectJPointcutAdvisor#2=Root
bean: class [org.springframework.aop.aspectj.AspectJPointcutAdvisor];
scope=;
abstract=false;
lazyInit=false;
autowireMode=0;
dependencyCheck=0;
autowireCandidate=true;
primary=false;
factoryBeanName=null;
factoryMethodName=null;
initMethodName=null;
destroyMethodName=null,
org.springframework.aop.aspectj.AspectJPointcutAdvisor#3=Root
bean:class [org.springframework.aop.aspectj.AspectJPointcutAdvisor];
scope=;
abstract=false;
lazyInit=false;
autowireMode=0;
dependencyCheck=0;
autowireCandidate=true;
primary=false;
factoryBeanName=null;
factoryMethodName=null;
initMethodName=null;
destroyMethodName=null,
org.springframework.aop.aspectj.AspectJPointcutAdvisor#0=Root
參考: