15-Spring AOP的底層實現原理JDKProxy&CGLIB
前一篇:14-Spring AOP程式設計https://blog.csdn.net/fsjwin/article/details/109480097
前面我們討論動靜態理的時候說過,想要實現動態代理需要滿足三個條件:
- 目標物件
- 介面 代理物件和目標物件的相同介面
- 增強功能
1.JDK proxy動態代理原理
先來對jdk的proxy底層原理進行分析。
通過下面一幅圖,應該可以對jdkproxy的代理細節有個深入的認識:
2.JDK proxy程式碼
JDKProxy.java
package proxy.jdk;
import proxy.service.UserService;
import proxy.service.impl.UserServiceImpl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author yuhl
* @Date 2020/11/3 22:23
* @Classname JDKProxy
* @Description JDK動態代理
*/
public class JDKProxy {
public static void main(String[] args) {
//目標物件
UserService userService = new UserServiceImpl();
InvocationHandler invocationHandler = new InvocationHandler() {
/**
*
* @param proxy 代理物件,暫時不用
* @param method 需要被增強的方法
* @param args 方法的返回值後
* @return 原方法的返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDKProxy.invoke 前增強");
Object ret = method.invoke(userService, args);
System.out.println("JDKProxy.invoke 後增強");
return ret;
}
};
UserService userServiceProxy = (UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), invocationHandler);
userService.login("yuhl", "1111");
userServiceProxy.login("yuhl", "1111");
}
}
3.JDK proxy學習這個動態代理有什麼意義呢?
前面我們學習了MethodInterceptor,他和jdkproxy什麼關係呢?一個是sun對動態dialing的實心,另一個是aop聯盟的實現。aop聯盟的實現更為友好吧。
學習這個jdkproxy有什麼意義呢?
意義就在於spring的底層就是使用的這個方法生成的proxy物件返回給我們的。這樣我們就知道了spring生成代理物件的原始碼。對於門寫程式碼有很好的的撐腰作用。
4.CGlib動態代理
和JDK動態代理一樣,cglib可以對一般的類驚醒動態代理,但是他的條件適應的,他的底層是整合了當前類,然後用super.login()方法,然後在前後進行加強。
也需要三個必要條件:
- 目標類
- 父類物件(介面)
- 增強程式碼
這點和jdkproxy一模一樣,唯一不一樣的是一個是介面、一個是一般的類
5.CGlib程式碼
- 目標類
package proxy.cglib;
import proxy.service.User;
/**
* @author yuhl
* @Date 2020/11/3 23:00
* @Classname StudentService
* @Description TODO
*/
public class StudentService {
public boolean login(String name,String password){
System.out.println("StudentService.login");
return true;
}
public void register(User user) {
System.out.println("StudentService.register");
}
}
- 測試類
package proxy.cglib;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author yuhl
* @Date 2020/11/3 23:01
* @Classname CjlibTest
* @Description TODO
*/
public class CjlibTest {
public static void main(String[] args) {
//目標類
StudentService studentService = new StudentService();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(studentService.getClass());
enhancer.setClassLoader(CjlibTest.class.getClassLoader());
MethodInterceptor methodInterceptor= new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CjlibTest.intercept 前");
Object rev = method.invoke(studentService,objects);
System.out.println("CjlibTest.intercept 後");
return rev;
}
};
enhancer.setCallback(methodInterceptor);
StudentService studentServiceProxy = (StudentService) enhancer.create();
studentServiceProxy.login("zhangsan", "211111");
//studentServiceProxy.login("yuhl", "3333");
}
}
- 測試結果
CjlibTest.intercept 前
StudentService.login
CjlibTest.intercept 後
6.另外一個大問題,那麼這個代理物件實在什麼時候建立的呢?
我們回頭想想應該不難想到肯定實在BeanPostProcessor的時候被建立的,看下圖:
- ProxyBeanPostProcessor.java程式碼
package proxy.service;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author yuhl
* @Date 2020/11/3 23:31
* @Classname ProxyBeanPostProcessor
* @Description 模擬spring底層生成代理物件的過程
*/
public class ProxyBeanPostProcessor implements BeanPostProcessor {
proxy.service.UserService userService = new proxy.service.impl.UserServiceImpl();
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
*
* @param bean 被修改的bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("ProxyBeanPostProcessor.invoke 前----------》");
Object rev = method.invoke(userService, args);
System.out.println("ProxyBeanPostProcessor.invoke 後----------》");
return rev;
}
});
// return bean;
}
}
- 配置檔案
<?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 https://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="proxy.service.impl.UserServiceImpl"/>
<!--模擬spring生成代理物件的過程-->
<bean id="proxyBeanPostProcessor" class="proxy.service.ProxyBeanPostProcessor"/>
</beans>
- 測試
@Test
public void test5() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext7.xml");
proxy.service.UserService userService = (proxy.service.UserService)ctx.getBean("userService");
userService.login("zhangsan","111111");
userService.regester(new User(2, "222222"));
}
- 測試結果
@Test
public void test5() {
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext7.xml");
proxy.service.UserService userService = (proxy.service.UserService)ctx.getBean("userService");
userService.login("zhangsan","111111");
userService.regester(new User(2, "222222"));
}
7.總結
到此我們明白了jdk代理和cglib代理的全部過程,代理均需要滿足三個條件:
- 代理隊形
- 介面(父類)
- 增強功能,
同時模擬了工廠在何時建立了代理物件就是在postProcessAfterInitialization的after方法的時候建立的。
相關文章
- Spring AOP概述、底層實現Spring
- AOP底層原理之CGlibCGLib
- ArrayList底層的實現原理
- HashMap底層實現原理HashMap
- NSDictionary底層實現原理
- AutoreleasePool底層實現原理
- MySQL Join的底層實現原理MySql
- MySQL索引底層實現原理MySql索引
- KVO的使用和底層實現原理
- MG--探究KVO的底層實現原理
- 【Spring AOP】AOP 底層實現原理 —— 動態代理類的建立(JDK、CGlib)、工廠如何加工原始物件SpringJDKCGLib物件
- php底層原理之陣列實現PHP陣列
- javascript事件機制底層實現原理JavaScript事件
- 面試官:說說反射的底層實現原理?面試反射
- iOS底層-KVC使用實踐以及實現原理iOS
- iOS底層原理總結 - 關聯物件實現原理iOS物件
- iOS底層原理總結 -- 利用Runtime原始碼 分析Category的底層實現iOS原始碼Go
- React-Router底層原理分析與實現React
- 面試必問:HashMap 底層實現原理分析面試HashMap
- 筆記-集合NSSet、字典NSDictionary的底層實現原理筆記
- iOS窺探KVO底層實現原理篇iOS
- HashMap的實現原理 HashMap底層實現,hashCode如何對應bucket?HashMap
- 深入理解Java中的底層阻塞原理及實現Java
- HashMap的底層原理HashMap
- Spring AOP的實現原理Spring
- AOP如何實現及實現原理
- LinkedList的底層實現
- Java集合類,從原始碼解析底層實現原理Java原始碼
- OC底層探索(十六) KVO底層原理
- AOP概述及實現原理
- AOP如何實現及其原理
- 【Spring】AOP實現原理Spring
- Spring AOP實現原理Spring
- 高效能的Redis之物件底層實現原理詳解Redis物件
- 七、真正的技術——CAS操作原理、實現、底層原始碼原始碼
- synchronized底層原理synchronized
- Netty的底層原理Netty
- Vue中的底層原理Vue