Spring框架-AOP核心
Spring AOP
AOP (Aspect Oriented Programming) 面向切面編程
OOP(Object Oriented Programming)面向?qū)ο缶幊蹋脤ο蟮乃枷雭硗晟瞥绦?/p>
AOP是的OOP的一個(gè)補(bǔ)充,是在另外一個(gè)維度上抽象出的對象。
具體是指程序運(yùn)行時(shí)動(dòng)態(tài)的將非業(yè)務(wù)代碼切入到業(yè)務(wù)代碼中,從而實(shí)現(xiàn)程序的解耦合,將非業(yè)務(wù)抽象成一個(gè)對象,對對象編程就是面向?qū)ο缶幊獭?/p>
在同樣的地方有相同的方法抽象成一個(gè)切面----代碼A切面對象。
AOP的優(yōu)點(diǎn):
可以降低模塊之間的耦合性
提高代碼的復(fù)用性
集中管理代碼的維護(hù)性
集中管理代碼的非義務(wù)代碼,便于維護(hù)
業(yè)務(wù)代碼不受非業(yè)務(wù)代碼的影響,邏輯更加清晰
理解AOP
創(chuàng)建接口的計(jì)算器類
java
package com.southwind.aop;
public interface Cal {
public int add(int num1,int num2);
public int sub(int num1,int num2);
public int mul(int num1,int num2);
public int div(int num1,int num2);
}
2.實(shí)現(xiàn)類:
package com.southwind.aop.impl;
import com.southwind.aop.Cal;
public class CalImpl implements Cal {
@Override
public int add(int num1, int num2) {
int result = num1+num2;
return result;
}
@Override
public int sub(int num1, int num2) {
int result = num1-num2;
return result;
}
@Override
public int mul(int num1, int num2) {
int result = num1*num2;
return result;
}
@Override
public int div(int num1, int num2) {
int result = num1/num2;
return result;
}
}
3.日志打印:
在每個(gè)方法開始的位置輸出參數(shù)的信息
在每個(gè)方法的結(jié)束的位置輸出結(jié)果信息
對于計(jì)算器而言,加減乘除是業(yè)務(wù)代碼,日志是非業(yè)務(wù)代碼。
AOP如何實(shí)現(xiàn)?:
使用動(dòng)態(tài)代理
代理首先具備CaLImpl的基礎(chǔ)功能,然后在這個(gè)基礎(chǔ)上擴(kuò)展日志功能
刪除CalImpl方法中的打印日志的代碼,只保留業(yè)務(wù)代碼
創(chuàng)建MyinvocationHandler類,實(shí)現(xiàn)IvocationHandler接口,生成動(dòng)態(tài)代理類
動(dòng)態(tài)代理類要?jiǎng)討B(tài)生成。
ClassLoader用來將動(dòng)態(tài)的類加載到虛擬機(jī)(JVM)中。
Proxy.newProxyInstance(類加載器《object.getClass.getClassLoder》,委托對象的接口《object.getClass().getInterfaces()》,this);
動(dòng)態(tài)創(chuàng)建代理類---方到實(shí)體類里面。
底層原理
1.接口:
```java
package com.southwind.aop;
public interface Cal {
public int add(int num1,int num2);
public int sub(int num1,int num2);
public int mul(int num1,int num2);
public int div(int num1,int num2);
}
2.代理對象:
package com.southwind.aop;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class MyinvocationHandler implements InvocationHandler {
//委托對象
private Object object=null;
//返回代理對象
public Object bind(Object object){
this.object=object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(),this);
}
?
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//實(shí)現(xiàn)業(yè)務(wù)代碼和非業(yè)務(wù)代碼調(diào)用
System.out.println(method.getName()+"方法的參數(shù)是:"+ Arrays.toString(args));
Object result=method.invoke(this.object,args);
System.out.println(method.getName()+"方法的參數(shù)是:"+ result);
return result;
}
}
```
3.實(shí)現(xiàn)類;
```java
package com.southwind.aop.impl;
import com.southwind.aop.Cal;
public class CalImpl implements Cal {
@Override
public int add(int num1, int num2) {
int result = num1+num2;
return result;
}
@Override
public int sub(int num1, int num2) {
int result = num1-num2;
return result;
}
@Override
public int mul(int num1, int num2) {
int result = num1*num2;
return result;
}
@Override
public int div(int num1, int num2) {
int result = num1/num2;
return result;
}
}
4.測試類:
?
?```java
package com.southwind.test;
import com.southwind.aop.Cal;
import com.southwind.aop.MyinvocationHandler;
import com.southwind.aop.impl.CalImpl;
public class Test10 {
public static void main(String[] args) {
//實(shí)例化委托對象
Cal cal = new CalImpl();
// cal.add(10,3);
// cal.div(10,3);
// cal.mul(10,3);
// cal.sub(10,3);
// 獲取代理對象
MyinvocationHandler myinvocationHandler= new MyinvocationHandler();
Cal proxy=(Cal)myinvocationHandler.bind(cal);
proxy.add(10,3);
}
}
上述代碼的動(dòng)態(tài)機(jī)制實(shí)現(xiàn)了業(yè)務(wù)代碼和非業(yè)務(wù)代碼的解耦合,這是SpringAOP的底層實(shí)現(xiàn)機(jī)制,不要這么復(fù)雜,有更好的方式。
Spring AOP的開發(fā)步驟:
1.創(chuàng)建切面類:
package com.southwind.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Array;
import java.util.Arrays;
@Component
@Aspect
public class LogAspect {
@Before("execution(public int com.southwind.aop.impl.CalImpl.*(..))")
public void before(JoinPoint joinPoint){
String name=joinPoint.getSignature().getName();
String args= Arrays.toString((joinPoint.getArgs()));
System.out.println(name+"方法的參數(shù)是"+args);
}
@After("execution(public int com.southwind.aop.impl.CalImpl.*(..))")
public void after(JoinPoint joinPoint){
String name=joinPoint.getSignature().getName();
System.out.println(name+"方法執(zhí)行完畢");
}
@AfterReturning(value = "execution(public int com.southwind.aop.impl.CalImpl.*(..))",returning = "result")
public void afterReturn(JoinPoint joinPoint,Object result){
String name=joinPoint.getSignature().getName();
System.out.println(name+"方法執(zhí)行完畢"+"結(jié)果是:"+result);
}
@AfterThrowing(value = "execution(public int com.southwind.aop.impl.CalImpl.*(..))",throwing = "ex")
public void afterTrowing(JoinPoint joinPoint,Exception ex){
String name= joinPoint.getSignature().getName();
System.out.println(name+"方法拋出異常"+ex);
}
}
2.委托類加上@Component
package com.southwind.aop.impl;
import com.southwind.aop.Cal;
import org.springframework.stereotype.Component;
@Component
public class CalImpl implements Cal {
@Override
public int add(int num1, int num2) {
int result = num1+num2;
return result;
}
@Override
public int sub(int num1, int num2) {
int result = num1-num2;
return result;
}
@Override
public int mul(int num1, int num2) {
int result = num1*num2;
return result;
}
@Override
public int div(int num1, int num2) {
int result = num1/num2;
return result;
}
}
3.配置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.southwind.aop"></context:component-scan>
<!-- 自動(dòng)代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
3測試類:
package com.southwind.aop.impl;
import com.southwind.aop.Cal;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext= new ClassPathXmlApplicationContext("spring-aop.xml");
Cal cal = (Cal)applicationContext.getBean("a");
System.out.println(cal.add(10,3));
}
}
@Component 將切面類加載到IoC容器中
@Aspect 表示類是一個(gè)切面類
@Before 表示方法執(zhí)行的時(shí)機(jī),execution表示的是切入點(diǎn)是CallImpl中執(zhí)行add方法之前執(zhí)行日志方法
@AfterReturning,表示方法的執(zhí)行時(shí)機(jī)是再業(yè)務(wù)方法返回結(jié)果:returning是將返回的業(yè)務(wù)代碼的返回的形參
@AfterThrowing:表示方法執(zhí)行是拋出的異常,throwing表示拋出的異常的處理形參
aop:aspectj-autoproxy ,Spring IoC容器會(huì)結(jié)合動(dòng)態(tài)代理對象自動(dòng)的生成代理對象,AOP底層就是通過動(dòng)態(tài)代理對象來實(shí)現(xiàn)的。
AOP的概念:
切面對象;根據(jù)切面抽象出來的對象,Callmpl所有的方法中需要加入日志的部分,抽象成一個(gè)切面對象
通知:切面對象具體執(zhí)行的代碼,即具體的非業(yè)務(wù)代碼,LoggerAspect對象打印日志的代碼
目標(biāo);被橫切的對象,即CallImpl將通知加入其中。
代理:切面對象、通知、目標(biāo)混合之后的結(jié)果,即時(shí)我門使用JDK動(dòng)態(tài)代理的機(jī)制創(chuàng)建對象
連接點(diǎn);需要被橫切的位置,即要通知要插入業(yè)務(wù)代碼的具體位置
總結(jié)
以上是生活随笔為你收集整理的Spring框架-AOP核心的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP_递归实现无限级分类
- 下一篇: hdu 4501三重包问题