Aop用于代码功能的横向扩展
schemaBased方式:
<bean id="a" class="com.bjsxt.pojoAop.TestA"></bean>
<!--配置扩展前的bean-->
<bean id="before" class="com.bjsxt.adviceAop.MyBefore"></bean>
<!--配置扩展后的bean-->
<bean id="after" class="com.bjsxt.adviceAop.MyAfter"></bean>
<!--配置扩展组装规则-->
<aop:config>
<!--指明要进行功能扩展的方法-->
<aop:pointcut id="my" expression="execution(* com.bjsxt.pojoAop.TestA.testA())"/>
<!--组件(配置规则)-->
<aop:advisor advice-ref="before" pointcut-ref="my"></aop:advisor>
<aop:advisor advice-ref="after" pointcut-ref="my"></aop:advisor>
</aop:config>
main方法:
public static void main(String[] args) {
//获取Spring容器对象
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationcontext-aop.xml");
//获取对象完成功能开发 C为a的接口
C c = (C) ac.getBean("a");
c.testA();
}
环绕通知 (用于代码量少时,方便简单):
类需要实现MethodInterceptor 接口
public class MyRound implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
//扩展前代码
System.out.println("环绕通知---前");
//调用原有代码--放行
Object proceed = methodInvocation.proceed();
//扩展后代码
System.out.println("环绕通知---后:"+proceed);
return proceed;
}
}
配置文件:
<!--环绕通知bean-->
<bean id="round" class="com.bjsxt.advice.MyRound"></bean>
<!--环绕通知-->
<aop:config>
<aop:advisor advice-ref="round" pointcut-ref="mp"></aop:advisor>
</aop:config>
异常通知:(出现异常时才触发,类似于try catch)
写异常类,实现ThrowsAdvice 接口
public class MyThrow implements ThrowsAdvice {
public void afterThrowing(Exception e){
System.out.println("我是异常通知:"+e.getMessage());
}
}
配置:
<!--异常通知bean-->
<bean id="throw" class="com.bjsxt.advice.MyThrow"></bean>
<!--配置组装规则-->
<aop:config>
<!--异常通知-->
<aop:advisor advice-ref="throw" pointcut-ref="mp"></aop:advisor>
</aop:config>
Aspect方式:
1、配置将增加的代码配置到一个类里面(无需接口)
ps:环绕通知需要加参数ProceedingJoinPoint
public class MyAdvice {
//前置通知
public void before(String name,int age){
System.out.println("我是前置通知"+name+age);
}
//后置通知
public void after(){
System.out.println("我是后置通知");
}
//环绕通知
public void myRound(ProceedingJoinPoint pp) throws Throwable {
//环绕前
System.out.println("环绕-前");
//放行
Object proceed = pp.proceed();
//环绕后
System.out.println("环绕-后");
}
//异常通知
public void myThrow(Exception ex){
System.out.println("我是异常通知:"+ex.getMessage());
}
}
2、配置文件(使用aspect标签):
<!--配置学生的bean-->
<bean id="stu" class="com.bjsxt.pojo.Student"></bean>
<!--配置通知bean-->
<bean id="advice" class="com.bjsxt.advice.MyAdvice"></bean>
<!--配置组装规则-->
<aop:config>
<aop:aspect ref="advice"><!--声明通知bean的ID-->
<!--声明切点-->
<aop:pointcut id="mp" expression="execution(* com.bjsxt.pojo.Student.testStudent(String,int)) and args(name,age)"/>
<!--前置通知-->
<aop:before method="before" pointcut-ref="mp" arg-names="name,age"></aop:before>
<!--后置通知-->
<aop:after-returning method="after" pointcut-ref="mp"></aop:after-returning>
<!--环绕通知-->
<aop:around method="myRound" pointcut-ref="mp"></aop:around>
<!--异常通知-->
<aop:after-throwing method="myThrow" pointcut-ref="mp" throwing="ex"></aop:after-throwing>-->
</aop:aspect>
</aop:config>
ps:
1、关于后置通知:
异常后继续执行:after
异常后不执行:after-returning
2、schemaBase与Aspect的异同点:
类的创建:
- aspect:只需要一个通知类,区分前后在aspect标签里
- schemaBase:几个新功能几个类,前后通知通过接口判断
参数问题:
- aspect:带参数很麻烦,需要在标签后配置类型arg-name
- schemaBase:可以直接使用
3、多个方法需要增加相同功能时:
当某个类下的同名方法都需要增加相同的功能时:
类名.方法名(..)
<!--声明切点-->
<aop:pointcut id="mp" expression="execution(* com.bjsxt.pojo.Student.testStudent(..))"/>
某类下所有方法时:
类名.*(..)
某包下所有类的所有方法:
包名.*.*(..)