什么是aop
1:AOP:Aspect Oriented Programming 的缩写,意思为面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
2:主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
AOP的实现方式
1预编译(Aspectj)
2运行期动态代理(JDK的动态代理,CGLIB动态代理)(SpringAOP,JBoosAOP)

通知的类型:

Spring框架中AOP的作用
1:提供了声明式的企业服务,特别是EJB的替代服务的声明
2:允许用户定制自己的方面,已完成oop与Aop的互补作用
image.png
image.png
基于配置的AOP实现

声明一个切面

上图的意思为把id为aBean的bean作为一个切面声明,切面的id为myAspect
声明一个切入点
(springAOP和Aspectj都支持的)

(springAOP支持的)

等等其他的,具体使用的时候可以查阅相关的切入点表达式
例子:
<bean id="moocAspect" class="com.imooc.aop.schema.advice.MoocAspect"></bean>
<bean id="aspectBiz" class="com.imooc.aop.schema.advice.biz.AspectBiz"></bean>
<aop:config>
<aop:aspect id="moocAspectAOP" ref="moocAspect">
<aop:pointcut expression="execution(* com.imooc.aop.schema.advice.biz.*Biz.*(..))" id="moocPiontcut"/>
</aop:aspect>
</aop:config>
通知advice
前置通知

返回后通知

异常后通知

最后通知(无论有无异常,最后都会执行)

环绕通知

环绕通知携带参数


<bean id="moocAspect" class="com.imooc.aop.schema.advice.MoocAspect"></bean>
<bean id="aspectBiz" class="com.imooc.aop.schema.advice.biz.AspectBiz"></bean>
<aop:config>
<aop:aspect id="moocAspectAOP" ref="moocAspect">
<aop:pointcut expression="execution(* com.imooc.aop.schema.advice.biz.*Biz.*(..))" id="moocPiontcut"/>切入点表达式
//<aop:before method="before" pointcut-ref="moocPiontcut"/>前置通知,方法为before
//<aop:after-returning method="afterReturning" pointcut-ref="moocPiontcut"/>返回后通知
//<aop:after-throwing method="afterThrowing" pointcut-ref="moocPiontcut"/> 异常后通知
//<aop:after method="after" pointcut-ref="moocPiontcut"/> 最后通知
//<aop:around method="around" pointcut-ref="moocPiontcut"/> 环绕通知
//<aop:around method="aroundInit" pointcut="execution(* com.imooc.aop.schema.advice.biz.AspectBiz.init(String, int))
and args(bizName, times)"/>
//<aop:declare-parents types-matching="com.imooc.aop.schema.advice.biz.*(+)"
implement-interface="com.imooc.aop.schema.advice.Fit"
default-impl="com.imooc.aop.schema.advice.FitImpl"/>
</aop:aspect>
</aop:config>
环绕通知:
public Object around(ProceedingJoinPoint pjp) {
Object obj = null;
try {
System.out.println("MoocAspect around 1.");执行前操作
obj = pjp.proceed();方法
System.out.println("MoocAspect around 2.");执行后操作
} catch (Throwable e) {
e.printStackTrace();
}
return obj;
}
环绕通知携带参数:
public Object aroundInit(ProceedingJoinPoint pjp, String bizName, int times) {
System.out.println(bizName + " " + times);
Object obj = null;
try {
System.out.println("MoocAspect aroundInit 1.");
obj = pjp.proceed();
System.out.println("MoocAspect aroundInit 2.");
} catch (Throwable e) {
e.printStackTrace();
}
return obj;
}
Introductions
简介允许一个切面声明一个实现指定接口的通知对象 ,并且提供一个接口实现类来代表这些对象
由<aop:aspect>中的<aop:declare-parents>元素声明该元素用于声明所匹配的类型拥有一个新的parent(因此得名)
image.png
types-matching匹配的类型
implement-interface实现的接口
default-impl接口实现类
public interface Fit {
void filter();
}
public class FitImpl implements Fit {
@Override
public void filter() {
System.out.println("FitImpl filter.");
}
}
@Test
public void testFit() {
Fit fit = (Fit)super.getBean("aspectBiz");
fit.filter();
}为这个类aspectBiz的强制指定一个父类为FitImpl
所有配置式的aspect只支持单例


使用事务的时候经常用到
例子:
配置文件
<context:component-scan base-package="com.imooc.aop.schema"></context:component-scan>
<aop:config>
<aop:aspect id="concurrentOperationRetry" ref="concurrentOperationExecutor">
<aop:pointcut id="idempotentOperation"
expression="execution(* com.imooc.aop.schema.advisors.service.*.*(..)) " />
<!-- expression="execution(* com.imooc.aop.schema.service.*.*(..)) and -->
<!-- @annotation(com.imooc.aop.schema.Idempotent)" /> -->
<aop:around pointcut-ref="idempotentOperation" method="doConcurrentOperation" />
</aop:aspect>
</aop:config>
<bean id="concurrentOperationExecutor" class="com.imooc.aop.schema.advisors.ConcurrentOperationExecutor">
<property name="maxRetries" value="3" />
<property name="order" value="100" />
</bean>
类
public class ConcurrentOperationExecutor implements Ordered {
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 1;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
int numAttempts = 0;
PessimisticLockingFailureException lockFailureException;
do {
numAttempts++;
System.out.println("Try times : " + numAttempts);
try {
return pjp.proceed();
} catch (PessimisticLockingFailureException ex) {
lockFailureException = ex;
}
} while (numAttempts <= this.maxRetries);
System.out.println("Try error : " + numAttempts);
throw lockFailureException;
}
}
Service类
@Service
public class InvokeService {
public void invoke() {
System.out.println("InvokeService ......");
}
public void invokeException() {
throw new PessimisticLockingFailureException("");
}
}
测试类:
@RunWith(BlockJUnit4ClassRunner.class)
public class TestAOPSchemaAdvisors extends UnitTestBase {
public TestAOPSchemaAdvisors() {
super("classpath:spring-aop-schema-advisors.xml");
}
@Test
public void testSave() {
InvokeService service = super.getBean("invokeService");
service.invoke();
System.out.println();
service.invokeException();
}
}
执行结果

第一次成功不再进行循环,第二次循环。
Spring Aop api



public class MoocBeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("MoocBeforeAdvice : " + method.getName() + " " +
target.getClass().getName());
}
}


public class MoocThrowsAdvice implements ThrowsAdvice {
public void afterThrowing(Exception ex) throws Throwable {
System.out.println("MoocThrowsAdvice afterThrowing 1");
}
public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable {
System.out.println("MoocThrowsAdvice afterThrowing 2 : " + method.getName() + " " +
target.getClass().getName());
}

public class MoocAfterReturningAdvice implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("MoocAfterReturningAdvice : " + method.getName() + " " +
target.getClass().getName() + " " + returnValue);
}
}

public class MoocMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("MoocMethodInterceptor 1 : " + invocation.getMethod().getName() + " " +
invocation.getStaticPart().getClass().getName());
Object obj = invocation.proceed();
System.out.println("MoocMethodInterceptor 2 : " + obj);
return obj;
}
}




public interface Lockable {
void lock();
void unlock();
boolean locked();
}
public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {
private static final long serialVersionUID = 6943163819932660450L;
private boolean locked;
public void lock() {
this.locked = true;
}
public void unlock() {
this.locked = false;
}
public boolean locked() {
return this.locked;
}
public Object invoke(MethodInvocation invocation) throws Throwable {
if (locked() && invocation.getMethod().getName().indexOf("set") == 0) {
throw new RuntimeException();
}
return super.invoke(invocation);
}
}
public class LockMixinAdvisor extends DefaultIntroductionAdvisor {
private static final long serialVersionUID = -171332350782163120L;
public LockMixinAdvisor() {
super(new LockMixin(), Lockable.class);
}
}

springAOP代理的核心类

foo引用ProxyFactoryBean,得到的对象是getOpject()方法创建的



创建一个基于接口的代理,getOpject()方法返回的就是target
image.png
配置:
<?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
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="moocBeforeAdvice" class="com.imooc.aop.api.MoocBeforeAdvice"></bean>
<bean id="moocAfterReturningAdvice" class="com.imooc.aop.api.MoocAfterReturningAdvice"></bean>
<bean id="moocMethodInterceptor" class="com.imooc.aop.api.MoocMethodInterceptor"></bean>
<bean id="moocThrowsAdvice" class="com.imooc.aop.api.MoocThrowsAdvice"></bean>
<!-- <bean id="bizLogicImplTarget" class="com.imooc.aop.api.BizLogicImpl"></bean> -->
<!-- <bean id="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut"> -->
<!-- <property name="mappedNames"> -->
<!-- <list> -->
<!-- <value>sa*</value> -->
<!-- </list> -->
<!-- </property> -->
<!-- </bean> -->
<!-- <bean id="defaultAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor"> -->
<!-- <property name="advice" ref="moocBeforeAdvice" /> -->
<!-- <property name="pointcut" ref="pointcutBean" /> -->
<!-- </bean> -->
<!-- <bean id="bizLogicImpl" class="org.springframework.aop.framework.ProxyFactoryBean"> -->
<!-- <property name="target"> -->
<!-- <ref bean="bizLogicImplTarget"/> -->
<!-- </property> -->
<!-- <property name="interceptorNames"> -->
<!-- <list> -->
<!-- <value>defaultAdvisor</value> -->
<!-- <value>moocAfterReturningAdvice</value> -->
<!-- <value>moocMethodInterceptor</value> -->
<!-- <value>moocThrowsAdvice</value> -->
<!-- </list> -->
<!-- </property> -->
<!-- </bean> -->
<!-- <bean id="bizLogicImplTarget" class="com.imooc.aop.api.BizLogicImpl"></bean> -->
<!-- <bean id="bizLogicImpl" class="org.springframework.aop.framework.ProxyFactoryBean"> -->
<!-- <property name="proxyInterfaces"> -->
<!-- <value>com.imooc.aop.api.BizLogic</value> -->
<!-- </property> -->
<!-- <property name="target"> -->
<!-- <bean class="com.imooc.aop.api.BizLogicImpl"></bean> -->
<!-- <ref bean="bizLogicImplTarget"/> -->
<!-- </property> -->
<!-- <property name="interceptorNames"> -->
<!-- <list> -->
<!-- <value>moocBeforeAdvice</value> -->
<!-- <value>moocAfterReturningAdvice</value> -->
<!-- <value>moocMethodInterceptor</value> -->
<!-- <value>moocThrowsAdvice</value> -->
<!-- <value>mooc*</value> -->
<!-- </list> -->
<!-- </property> -->
<!-- </bean> -->
<bean id="baseProxyBean" class="org.springframework.aop.framework.ProxyFactoryBean"
lazy-init="true" abstract="true"></bean>
<bean id="bizLogicImpl" parent="baseProxyBean">
<property name="target">
<bean class="com.imooc.aop.api.BizLogicImpl"></bean>
</property>
<property name="proxyInterfaces">
<value>com.imooc.aop.api.BizLogic</value>
</property>
<property name="interceptorNames">
<list>
<value>moocBeforeAdvice</value>
<value>moocAfterReturningAdvice</value>
<value>moocMethodInterceptor</value>
<value>moocThrowsAdvice</value>
</list>
</property>
</bean>
</beans>
实现bean:
public class BizLogicImpl implements BizLogic {
public String save() {
System.out.println("BizLogicImpl : BizLogicImpl save.");
return "BizLogicImpl save.";
// throw new RuntimeException();
}
}
接口:
public interface BizLogic {
String save();
}
测试类:
@RunWith(BlockJUnit4ClassRunner.class)
public class TestAOPAPI extends UnitTestBase {
public TestAOPAPI() {
super("classpath:spring-aop-api.xml");
}
@Test
public void testSave() {
BizLogic logic = (BizLogic)super.getBean("bizLogicImpl");
logic.save();
}
}
打印结果:





实现Interceptor的拦截器。





Aspectj

Aspectj的两种方式




切入点定义方式

public class MoocAspect {
@Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")
//biz结尾的方法
public void pointcut() {}
//包下的任何类
@Pointcut("within(com.imooc.aop.aspectj.biz.*)")
public void bizPointcut() {}
}








@Component
@Aspect
public class MoocAspect {
@Pointcut("execution(* com.imooc.aop.aspectj.biz.*Biz.*(..))")
public void pointcut() {}
@Pointcut("within(com.imooc.aop.aspectj.biz.*)")
public void bizPointcut() {}
@Before("pointcut()")
public void before() {
System.out.println("Before.");
}
@Before("pointcut() && args(arg)")
public void beforeWithParam(String arg) {
System.out.println("BeforeWithParam." + arg);
}
@Before("pointcut() && @annotation(moocMethod)")
public void beforeWithAnnotaion(MoocMethod moocMethod) {
System.out.println("BeforeWithAnnotation." + moocMethod.value());
}
@AfterReturning(pointcut="bizPointcut()", returning="returnValue")
public void afterReturning(Object returnValue) {
System.out.println("AfterReturning : " + returnValue);
}
@AfterThrowing(pointcut="pointcut()", throwing="e")
public void afterThrowing(RuntimeException e) {
System.out.println("AfterThrowing : " + e.getMessage());
}
@After("pointcut()")
public void after() {
System.out.println("After.");
}
@Around("pointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("Around 1.");
Object obj = pjp.proceed();
System.out.println("Around 2.");
System.out.println("Around : " + obj);
return obj;
}
}
@Service
public class MoocBiz {
@MoocMethod("MoocBiz save with MoocMethod.")
public String save(String arg) {
System.out.println("MoocBiz save : " + arg);
// throw new RuntimeException(" Save failed!");
return " Save success!";
}
}


网友评论