一、通知(一般以前置通知为例)
&&一个普通的类 -> 有特定功能的类
a.继承类 b.实现接口 c.注解 d.配置
1.基于实现接口的AOP实现
a.现将需要配置通知的方法所在的类纳入IOC容器;
<!-- 配置addStudent方法所在的类 -->
<bean id="studentService" class="com.feng.service.impl.StudentServiceImpl">
<property name="studentDao" ref="studentDao"></property>
</bean>
<!-- 配置前置通知 -->
<bean id="logBefore" class="com.feng.aop.LogBefore"></bean>
b.通过实现接口或者继承类将普通类变为通知类;
public class LogBefore implements MethodBeforeAdvice{
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("前置通知...");
}
}
c.配置applicationContext.xml文件
<!-- 将add方法和前置通知想连接-->
<aop:config>
<!--设置切入点(起点)-->
<aop:pointcut expression="execution(public void com.feng.service.impl.StudentServiceImpl.addStudent(com.feng.entity.Student))" id="pointcut"/>
<!--设置连接点(终点)pointcut-ref是线->
<aop:advisor advice-ref="logBefore" pointcut-ref="pointcut"/>
</aop:config>
各种通知的接口:
2.基于注解的AOP实现
a.现将需要配置通知的方法所在的类纳入IOC容器;
b.开启注解对AOP的支持,不需要对应包的扫描器;
<!-- 使用注解实现AOP -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
c.不再需要连线了因为如下已经把方法和通知连起来了:
@Component("logAnnotation")
@Aspect
public class LogAspectAnnotation {
@Before("execution(public * addStudent(..))")//直接定义切入点
public void myBefore() { //紧跟这就是通知,相当于连起来了
System.out.println("《注解形式-前置通知》");
}
}
d.通过注解形式实现的AOP,如果想获取目标对象的参数,需要使用对象:JoinPoint,获取返回值为returning;
//后置通知
@AfterReturning( pointcut= "execution(public * addStudent(..))" ,returning="returningValue" )
public void myAfter(JoinPoint jp,Object returningValue) {//returningValue是返回值,但需要告诉spring
System.out.println("《注解形式-后置通知》:目标对象:"
+jp.getTarget()+",方法名:"+jp.getSignature().getName()
+",参数列表:"+ jp.getArgs().length+",返回值:"+returningValue );
}
各种通知的注解:
通知类型 | 注解 |
前置通知 | @Before |
后置通知 | @AfterReturning |
异常通知 | @AfterThrowing |
环绕通知 | @Around |
最终通知 | @After |
3.基于配置Schema的AOP实现
a.创建一个普通类作为通知类,并纳入IOC容器;
public class LogSchema {
//后置通知方法 :JoinPoint适用于注解
public void afterReturning(JoinPoint jp,Object returnValue) throws Throwable {
System.out.println("后置通知:目标对象:"+jp.getThis()+",调用的方法名:"+jp.getSignature().getName()+",方法的参数个数:"+jp.getArgs().length+",方法的返回值:"+returnValue);
}
public void before() {
System.out.println("前置通知...");
}
public void whenException(JoinPoint jp,NullPointerException e) {
System.out.println(">>>>>>>>>>>>>>>>异常:" +e.getMessage());
}
//注意:环绕通知 会返回目标方法的返回值,因此返回值为Object
public Object around(ProceedingJoinPoint jp) {
System.out.println("环绕通知:前置通知");
Object result = null ;
try {
result = jp.proceed() ;//执行方法
System.out.println(""+jp.getSignature().getName()+","+result);
System.out.println("环绕通知:后置通知");
}catch(Throwable e) {
System.out.println("环绕通知:异常通知");
}
return result ;
}
}
<!-- 将准备转为 通知的类 纳入ioc容器 -->
<bean id="logSchema" class="org.lanqiao.aop.LogSchema"></bean>
b.配置applicationContext.xml文件:
<aop:config>
<!-- 切入点(连接线的一端:业务类的具体方法) -->
<aop:pointcut expression="execution
(public * com.feng.service.impl.StudentServiceImpl.addStudent(..))" id="pcSchema"/>
<!-- schema方式 -->
<aop:aspect ref="logSchema">
<!-- 连接线:连接 业务 addStudent和前置通知before -->
<aop:before method="before" pointcut-ref="pcSchema"/>
<!-- 连接线:连接 业务 addStudent和后置通知afterReturning -->
<aop:after-returning method="afterReturning" returning="returnValue"
pointcut-ref="pcShema"/>
<aop:after-throwing method="whenException" pointcut-ref="pcSchema" throwing="e"/>
</aop:aspect>
</aop:config>