AOP術語
1.target:目標類,需要被代理的類。例如:UserService
2.Joinpoint(連接點):所謂連接點是指那些可能被攔截到的方法。例如:所有的方法
3**.PointCut** 切入點:已經被增強的連接點。例如:addUser()
4.advice 通知/增強,增強代碼。例如:after、before
5 . Weaving(織入):是指把增強advice應用到目標對象target來創建新的代理對象proxy的過程.
6.proxy 代理類
7 . Aspect(切面): 是切入點pointcut和通知advice的結合,一個切入點和一個通知,組成成一個特殊的面。
cglib
package com.spring.cglb;
//切面類
public class MyAspect {
public void before() {
System.out.println("開啓事物");
}
public void after() {
System.out.println("提交事務");
}
}
package com.spring.cglb;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Service;
@Service
public class MyBeanFactory {
public static UserServiceImpl getServiceInstance() {
final MyAspect aspect = new MyAspect();
final UserServiceImpl userService = new UserServiceImpl();
Enhancer e = new Enhancer();
e.setSuperclass(userService.getClass());
//回調函數
e.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy proxymethod)
throws Throwable {
aspect.before();
Object obj = method.invoke(userService, args);
aspect.after();
return obj;
}
});
// 創建代理類
UserServiceImpl proxyService = (UserServiceImpl) e.create();
return proxyService;
}
}
AOP聯盟通知類型
AOP聯盟爲通知Advice定義了org.aopalliance.aop.Advice
Spring按照通知Advice在目標類方法的連接點位置,可以分爲5類
前置通知 org.springframework.aop.MethodBeforeAdvice
在目標方法執行前實施增強
後置通知 org.springframework.aop.AfterReturningAdvice
在目標方法執行後實施增強
環繞通知 org.aopalliance.intercept.MethodInterceptor
在目標方法執行前後實施增強
異常拋出通知 org.springframework.aop.ThrowsAdvice
在方法拋出異常後實施增強
引介通知 org.springframework.aop.IntroductionInterceptor
在目標類中添加一些新的方法和屬性
Aop半自動代理
package com.spring.semiauto;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
//切面類 在切面l類中確定通知類型 實現不同的接口 使用環繞通知
public class MyAspect implements MethodInterceptor {
public void before() {
System.out.println("開啓事物");
}
public void after() {
System.out.println("提交事務");
}
@Override
public Object invoke(MethodInvocation m) throws Throwable {
this.before();
// 手動執行目標方法
Object obj = m.proceed();
this.after();
return obj;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- target類 -->
<bean id="UserServiceId" class="com.spring.semiauto.UserServiceImpl"></bean>
<!-- 切面類 -->
<bean id="MyAspect" class="com.spring.semiauto.MyAspect"></bean>
<!-- 創建代理類
使用工廠bean FractoryBean,底層調用getObjiect() ,返回bean
proxyFractoryBean 用於創建代理工廠 生成特殊代理對象
interfaces 確定代理的接口們
target 注入目標類
interceptorNames 切面類名稱
optimize :強制使用cglib
底層的原理是:
判斷有沒有接口 有接口使用jdk代理
沒有接口使用cglib代理
聲明optimize 使用cglib
-->
<bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean" >
<property name="interfaces" value="com.spring.semiauto.UserService"></property>
<property name="target" ref="UserServiceId"></property>
<property name="interceptorNames" value="MyAspect"></property>
</bean>
</beans>
AOP自動代理
導入jar包: 切入點表達式jar
引入命名空間
<?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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- target類 -->
<bean id="UserService" class="com.spring.auto.UserServiceImpl"></bean>
<!-- 切面類 -->
<bean id="MyAspect" class="com.spring.auto.MyAspect"></bean>
<!-- aop編程 -->
<aop:config>
<aop:pointcut expression="execution(* com.spring.auto.UserServiceImpl.*(..))" id="Mypoincut"/>
<aop:advisor advice-ref="MyAspect" pointcut-ref="Mypoincut"/>
</aop:config>
</beans>
AspectJ
aspectj 通知類型
before:前置通知(應用:各種校驗)
在方法執行前執行,如果通知拋出異常,阻止方法運行
afterReturning:後置通知(應用:常規數據處理)
方法正常返回後執行,如果方法中拋出異常,通知無法執行
必須在方法執行後才執行,所以可以獲得方法的返回值。
around:環繞通知(應用:十分強大,可以做任何事情)
方法執行前後分別執行,可以阻止方法的執行必須手動執行目標方法
afterThrowing:拋出異常通知(應用:包裝異常信息)
方法拋出異常後執行,如果方法沒有拋出異常,無法執行
after:最終通知(應用:清理現場)
方法執行完畢後執行,無論方法中是否出現異常
aspectj編程
package com.spring.aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
//切面類
public class MyAspect {
public void before(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println("前置通知:" + "方法名。。。。" + name);
}
public void afterReturning(JoinPoint jp, Object ret) {
System.out.println("後置通知");
System.out.println(ret);
}
public void after(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println("最終通知:" + "方法名。。。。" + name);
}
public Object MyArround(ProceedingJoinPoint pjp, Object ret) throws Throwable {
this.before(pjp);
Object object = pjp.proceed();
this.afterReturning(pjp, ret);
return object;
}
public void MyAfterThrowable(JoinPoint jp, Throwable e) {
String name = jp.getSignature().getName();
System.out.println("異常:" + name + "..." + e.getMessage());
}
}
<?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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 目標類 -->
<bean id="UserService" class="com.spring.aspectj.UserServiceImpl"></bean>
<!-- 切面類 -->
<bean id="MyAspect" class="com.spring.aspectj.MyAspect"></bean>
<!-- 前置通知配置 ref 引入切面 pointcut 切入點表達式 此表達式只能當前通知使用 pointcut 切入點引用 可與其他通知共享 -->
<aop:config>
<aop:aspect ref="MyAspect">
<aop:pointcut
expression="execution(*
com.spring.aspectj.UserServiceImpl.*(..))"
id="Mypointcut" />
<aop:before method="before" pointcut-ref="Mypointcut" />
</aop:aspect>
</aop:config>
<!-- 最終通知 -->
<aop:config>
<aop:aspect ref="MyAspect">
<aop:pointcut
expression="execution(*
com.spring.aspectj.UserServiceImpl.*(..))"
id="Mypointcut" />
<aop:after method="after" pointcut-ref="Mypointcut" />
</aop:aspect>
</aop:config>
<!-- 環繞通知 -->
<aop:config>
<aop:aspect ref="MyAspect">
<aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
id="Mypointcut" />
<aop:around method="MyArround" pointcut-ref="Mypointcut" />
</aop:aspect>
</aop:config>
<!-- 異常通知 -->
<aop:config>
<aop:aspect ref="MyAspect">
<aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
id="Mypointcut" />
<aop:after-throwing method="MyAfterThrowable"
pointcut-ref="Mypointcut" throwing="e" />
</aop:aspect>
</aop:config>
<!-- 後置通知 -->
<aop:config>
<aop:aspect ref="MyAspect">
<aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
id="Mypointcut" />
<aop:after-returning method="afterReturning"
pointcut-ref="Mypointcut" returning="ret" />
</aop:aspect>
</aop:config>
</beans>
使用註解
//切面類
@Component
@Aspect
public class MyAspect {
//創建切入點表達式
@Pointcut("execution(* com.spring.aop_annotation.UserServiceImpl.*(..))")
public void MyPointCut() {
}
@Before("MyPointCut()")
public void before(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println("前置通知:" + "方法名。。。。" + name);
}
@AfterReturning(value = "MyPointCut()", returning = "ret")
public void afterReturning(JoinPoint jp, Object ret) {
System.out.println("後置通知");
System.out.println(ret);
}
@After("MyPointCut()")
public void after(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println("最終通知:" + "方法名。。。。" + name);
}
@Around("MyPointCut()")
public Object MyArround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("前");
Object object = pjp.proceed();
System.out.println("後");
return object;
}
@AfterThrowing(value = "MyPointCut()", throwing = "e")
public void MyAfterThrowable(JoinPoint jp, Throwable e) {
String name = jp.getSignature().getName();
System.out.println("異常:" + name + "..." + e.getMessage());
}
}
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.spring.aop_annotation"></context:component-scan>
<!-- 使aop註解生效 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>