Java AOP動態(tài)代理詳細(xì)介紹
1.IOC與AOP概念
IOC:控制反轉(zhuǎn),把對象創(chuàng)建和對象之間的調(diào)用過程,交給Spring進(jìn)行管理。使用IOC的目的是為了降低耦合度。
AOP:面向切面編程,通過預(yù)編譯方式和運(yùn)行期間動態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)。AOP是OOP的延續(xù),是軟件開發(fā)中的一個(gè)熱點(diǎn),也是Spring框架中的一個(gè)重要內(nèi)容,是函數(shù)式編程的一種衍生范型。利用AOP可以對業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開發(fā)的效率。AOP的底層實(shí)現(xiàn)是基于動態(tài)代理(實(shí)現(xiàn)方式是當(dāng)切入接口時(shí),使用JDK原生動態(tài)代理;當(dāng)切入普通方法時(shí),使用cglib動態(tài)代理)。
2.為何使用動態(tài)代理
隨著業(yè)務(wù)的不斷擴(kuò)展:
(1)日志功能:如果日志代碼修改,需要修改多處。
(2)校驗(yàn)功能:如果多處需要校驗(yàn),需要修改多處。
這時(shí)就需要使用動態(tài)代理來解決問題,動態(tài)代理的實(shí)現(xiàn)方式有兩種:
[1]JDK原生動態(tài)代理:缺點(diǎn)是必須基于接口完成
[2]cglib動態(tài)代理:他可以不用基于接口完成
2.1 JDK原生動態(tài)代理
?
2.1.1 MathService接口類
public interface MathService { //+ public Double add(double a,double b); //- public Double sub(double a,double b); //* public Double mul(double a,double b); /// public Double div(double a,double b); }
2.1.2 MathServiceImpl實(shí)現(xiàn)接口類
public class MathServiceImpl implements MathService{ @Override public Double add(double a, double b) { Double result=a+b; return result; } @Override public Double sub(double a, double b) { Double result=a-b; return result; } @Override public Double mul(double a, double b) { Double result=a*b; return result; } @Override public Double div(double a, double b) { Double result=a/b; return result; } }
2.1.3 ProxyFactory動態(tài)代理工廠
public class ProxyFactory { //被代理對象 private Object target; public ProxyFactory(Object target) { this.target = target; } //獲取代理對象 public Object getProxy(){ /** * ClassLoader loader, 被代理對象的類加載器 * Class<?>[] interfaces, 被代理對象實(shí)現(xiàn)的接口 * InvocationHandler h: 當(dāng)代理對象執(zhí)行被代理的方法時(shí),會觸發(fā)該對象中的invoke功能 */ ClassLoader loader=target.getClass().getClassLoader(); Class<?>[] interfaces=target.getClass().getInterfaces(); InvocationHandler h=new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //可以加上需要的非業(yè)務(wù)代碼 //method.getName()獲取方法名 // Arrays.asList(args)獲取輸入值 System.out.println("this is "+method.getName()+" method begin with"+ Arrays.asList(args)); //method:表示代理對象要代理的方法 //invoke:回調(diào)該函數(shù) //args:方法需要的參數(shù) Object result = method.invoke(target, args);//代理對象回調(diào)該方法 return result; } }; //先寫此處方法,才可找到上述三個(gè)方法填寫方式 Object o = Proxy.newProxyInstance(loader, interfaces, h); return o; } }
2.1.4 測試類
public class Test01 { public static void main(String[] args) { MathServiceImpl target=new MathServiceImpl(); ProxyFactory proxyFactory=new ProxyFactory(target); MathService proxy = (MathService) proxyFactory.getProxy(); Double add = proxy.add(15.0, 5.0); System.out.println(add); } }
2.2 cglib動態(tài)代理
?
2.2.1 MathServiceImpl類
public class MathServiceImpl{ public Double add(double a, double b) { Double result=a+b; return result; } public Double sub(double a, double b) { Double result=a-b; return result; } public Double mul(double a, double b) { Double result=a*b; return result; } public Double div(double a, double b) { Double result=a/b; return result; } }
2.2.2 ProxyFactory動態(tài)代理工廠
注意:
(1)引入cglib的jar包.
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
(2)創(chuàng)建一個(gè)代理類工廠并實(shí)現(xiàn)接口MethodInterceptor
public class ProxyFactory implements MethodInterceptor { private Object target; public ProxyFactory(Object target) { this.target = target; } //獲取代理對象 public Object getProxy(){ Enhancer enhancer=new Enhancer(); //指定被代理對象的父類 enhancer.setSuperclass(target.getClass()); //指定回調(diào)類 enhancer.setCallback(this); //創(chuàng)建代理對象 return enhancer.create(); } //當(dāng)代理對象執(zhí)行代理方法時(shí)觸發(fā)的方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // System.out.println("before++++++++++++++++++++"); // Object result = method.invoke(target, args); //可以加上需要的非業(yè)務(wù)代碼 //method.getName()獲取方法名 // Arrays.asList(args)獲取輸入值 System.out.println("this is "+method.getName()+" method begin with"+ Arrays.asList(args)); //method:表示代理對象要代理的方法 //invoke:回調(diào)該函數(shù) //args:方法需要的參數(shù) Object result = method.invoke(target, args);//代理對象回調(diào)該方法 return result; } }
2.2.3 測試類
public class Test01 { public static void main(String[] args) { MathServiceImpl target=new MathServiceImpl(); ProxyFactory proxyFactory=new ProxyFactory(target); MathServiceImpl proxy = (MathServiceImpl) proxyFactory.getProxy(); Double add = proxy.add(1, 2); System.out.println(add); } }
3.AOP動態(tài)代理
3.1 添加對應(yīng)依賴
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.15.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.15.RELEASE</version> </dependency>
3.2 配置spring.xml文件
<?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: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 https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--包掃描--> <context:component-scan base-package="com.qy151wd.proxy.proxy.aop"/> <!--開啟aop注解--> <aop:aspectj-autoproxy/> </beans>
3.3 MathService接口類
public interface MathService { public Double add(double a, double b); public Double sub(double a, double b); public Double mul(double a, double b); public Double div(double a, double b); }
3.4 MathServiceImpl實(shí)現(xiàn)接口類
@Service public class MathServiceImpl implements MathService { @Override public Double add(double a, double b) { Double result=a+b; return result; } @Override public Double sub(double a, double b) { Double result=a-b; return result; } @Override public Double mul(double a, double b) { Double result=a*b; return result; } @Override public Double div(double a, double b) { Double result=a/b; return result; } }
3.5 LogAspect類
@Service //若是使用@component也可以 @Aspect //表示該類為切面類 public class LogAspect { //任意返回類型 aop包下的所有類都有切面日志 使用通配符 //第一個(gè)*:修飾符和返回值類型 //第二個(gè)*:所有類 //第三個(gè)*:所有方法 @Before("execution(* com.qy151wd.proxy.proxy.aop.*.*(..))") public void before(){ System.out.println("方法執(zhí)行前的日志"); } @After("execution(* com.qy151wd.proxy.proxy.aop.*.*(..))") //總會被執(zhí)行,不管有沒有異常 public void after(){ System.out.println("方法執(zhí)行后的日志"); } @AfterReturning("execution(* com.qy151wd.proxy.proxy.aop.*.*(..))")//只有碰到return后才會執(zhí)行 public void afterReturning(){ System.out.println("碰到return后執(zhí)行"); } @AfterThrowing("execution(* com.qy151wd.proxy.proxy.aop.*.*(..))")//異常通知 public void afterThrowing(){ System.out.println("出現(xiàn)異常了"); } }
3.6 測試類
public class Test01 { public static void main(String[] args) { //從spring容器中獲取 ApplicationContext app=new ClassPathXmlApplicationContext("spring.xml"); MathService mathService = (MathService) app.getBean("mathServiceImpl"); Double add = mathService.add(10, 5); System.out.println(add); } }
到此這篇關(guān)于Java AOP動態(tài)代理詳細(xì)介紹的文章就介紹到這了,更多相關(guān)Java AOP動態(tài)代理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java樹形結(jié)構(gòu)數(shù)據(jù)生成導(dǎo)出excel文件方法記錄
最近好像得罪了poi,遇到的都是導(dǎo)出word、Excel、pdf的問題,下面這篇文章主要給大家介紹了關(guān)于Java樹形結(jié)構(gòu)數(shù)據(jù)生成導(dǎo)出excel文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2021-10-10Java并發(fā)編程之ConcurrentLinkedQueue解讀
這篇文章主要介紹了Java并發(fā)編程之ConcurrentLinkedQueue解讀,非阻塞的實(shí)現(xiàn)方式則可以使用循環(huán)CAS的方式來實(shí)現(xiàn),而ConcurrentLinkedQueue就是juc包中自帶的經(jīng)典非堵塞方式實(shí)現(xiàn)的工具類,需要的朋友可以參考下2023-12-12Android開發(fā)中實(shí)現(xiàn)用戶注冊和登陸的代碼實(shí)例分享
這篇文章主要介紹了Android開發(fā)中實(shí)現(xiàn)用戶注冊和登陸的代碼實(shí)例分享,只是實(shí)現(xiàn)基本功能,界面華麗度就請忽略啦XD 需要的朋友可以參考下2015-12-12Java實(shí)現(xiàn)冒泡排序與雙向冒泡排序算法的代碼示例
這篇文章主要介紹了Java實(shí)現(xiàn)冒泡排序與雙向冒泡排序算法的代碼示例,值得一提的是所謂的雙向冒泡排序并不比普通的冒泡排序效率來得高,注意相應(yīng)的時(shí)間復(fù)雜度,需要的朋友可以參考下2016-04-04springboot后端配置多個(gè)數(shù)據(jù)源、Mysql數(shù)據(jù)庫的便捷方法
實(shí)現(xiàn)springboot 后端配置多個(gè)數(shù)據(jù)源、Mysql數(shù)據(jù)庫,只需要新建 Mapper、實(shí)體類 相應(yīng)的文件夾,將不同數(shù)據(jù)源的文件保存到對應(yīng)的文件夾下,添加綁定數(shù)據(jù)庫配置Config,就可以輕松完成2021-08-08Java通過jersey實(shí)現(xiàn)客戶端圖片上傳示例
本篇文章主要介紹了Java通過jersey實(shí)現(xiàn)客戶端圖片上傳示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03