Aop 的作用
Aop: 面向切面編程
aop 的主要作用是運行一個函數的前后,運行另外的函數。
例子: 我們以一個日志為例,我們運行一個函數,需要記錄這個函數的運行時間 和他的運行結果
最簡單的函數
public class SimpleExample implements SExample {
@Override
public String orinFun(String arg){
return arg;
}
}
最簡單的寫法
我們直接在該函數記錄時間和結果
public String orinFun(String arg){
System.out.println("運行時間"+new Date().toString());
System.out.println("結果"+arg);
return arg;
}
當我們需要打印多個函數的運行時間這樣的寫法就非常冗余,且不易擴展,我們可以通過代理來解決。
代理
接口
public interface SExample {
String orinFun(String arg);
}
代理
public class SimpleProxy implements InvocationHandler {
private Object obj;
public SimpleProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();//你也可以根據代理名字的不同,做不同的代理方式 if(methodName.equals("*"))
System.out.println("運行時間"+new Date().toString());
Object res = method.invoke(obj, args);
System.out.println("結果"+res);
return res;
}
}
測試
@Test
void tesProxy(){
SimpleExample simpleExample = new SimpleExample();
SExample simpleExampleProxy = (SExample) Proxy.newProxyInstance(SimpleProxy.class.getClassLoader(),
new Class<?>[]{SExample.class},new SimpleProxy(simpleExample));
simpleExampleProxy.orinFun("test");
}
這樣寫就很方便了,一個類只需要寫一個代理就行
spring boot 提供更加方便的寫法就是aop
AOP的使用
1.引入包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.在啟動類上添加@EnableAspectJAutoProxy(exposeProxy = true)
即只有exposeProxy為true時,才會把proxy動態代理對象設置到AopContext上下文中。
@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
3.定義切片類
A.在類前面加上 @Aspect @Component注解
B. 定義切面 @Pointcut("execution(* com.example.demo.HelloWorld.*(..))"),既在那些函數外增添操作
C.定義具體的執行操作
D.什么時候執行操作 @Before @after AfterThrowing...
@Aspect
@Component
public class AopHandler {
@Pointcut("execution(* com.example.demo.HelloWorld.*(..))")
public void test(){
}
@Before("test()")
public void before() throws Throwable {
System.out.println("代理----前----CurrentTime = " + System.currentTimeMillis());
}
@After("test()")
public void afterReturning() throws Throwable {
System.out.println("代理----后----CurrentTime = " + System.currentTimeMillis());
}
}
Aop Around
我們可以將 before 和 after 和 afterthrowing 都放在Around 來做,更加的方便
@Aspect
@Component
public class AopDetailHandler {
@Pointcut("execution(* com.example.demo.DetailTest.print(..))")
public void pointCut(){
}
@Pointcut("execution(* com.example.demo.DetailTest.doPrint(String))")
public void pointCut2(){
}
@Before("pointCut()")
public void before(JoinPoint joinPoint) throws Throwable {
System.out.println("得到切片的參數"+Arrays.toString(joinPoint.getArgs()));
System.out.println("得到運行的類"+joinPoint.getSignature());
System.out.println("代理----前----CurrentTime = " + System.currentTimeMillis());
}
@Around("pointCut2()")
public Object run1(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// before
// 獲取方法名
String methodName = proceedingJoinPoint.getSignature().toString();
System.out.println("方法名"+methodName);
Object[] args = proceedingJoinPoint.getArgs();
System.out.println("參數"+ Arrays.toString(args));
// 獲取掉切片目標類
String entity = proceedingJoinPoint.getTarget().getClass().getName();
System.out.println("獲取調切片"+entity);
Object result = null;
try {
result = proceedingJoinPoint.proceed();//test方法的返回值
// after
System.out.println(result.toString());
} catch (Exception ex) {
// after throwing
System.out.println(ex.toString());
}
return result;
}
}