一、概述
Spring在此只是使用了和AspectJ一样的注解,但并没有使用AspectJ的编译器或者织入器,底层依然使用的是Spring AOP,依然是在运行时动态生成AOP代理,并不依赖AspectJ的编译器或者织入器。
二、例子与注释
1、定义Aspect与@Before增强处理
package com.aspect.service;
//定义一个接口
public interface Hello {
public void sayHello();
public void addUser(String name,String pass);
}
定义一个切面Bean
当启动@Aspect支持后,只要在Spring容器配置一个带@Aspect注解的Bean,Spring会自动识别该Bean,并将该Bean作为切面处理
package com.aspect.service;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
//定义一个切面类,用@Aspect修饰,表示这个为切入类
@Aspect
public class AuthAspect {
//匹配包下所有的类的sayHello方法
//匹配的方法执行作为切入点
@Pointcut("execution(* *.sayHello(..))")
/*
* 第一个*号为返回类型,表示所有类型
* 第二个星号表示包,这里表示所有的包
* (..)表示任何参数
*/
private void select(){
System.out.println("==============启动===============");
}
//@Before增强处理,指定切入点
@Before("select()")
public void authority(){
System.out.println("模拟执行权限检查");
}
@Before("select()")
public void init(){
System.out.println("启动测试");
}
@After("select()")
public void destory(){
System.out.println("结束测试后");
}
}
目标方法:
package com.aspect.service.impl;
import org.springframework.stereotype.Component;
import com.aspect.service.Hello;
@Component("helloImpl") //注入bean
public class HelloImpl implements Hello{
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("执行Hello组件的sayHello()方法");
}
public void addUser(String name, String pass) {
// TODO Auto-generated method stub
System.out.println("执行Hello组件的addUser添加用户:"+name);
}
}
配置文件:
<context:annotation-config/>
<!-- 自动扫描指定包及其子包下的所有bean类 -->
<context:component-scan base-package="com.aspect.service,com.aspect.service.impl,com.home.bean,com.home.model">
<!-- 只是以Axe结尾的类当成Spring容器中的bean -->
<!-- type:指定过滤器类型
1.annotation:Annotation过滤器,该过滤器需要指定一个Annotation名,如lee.AnnotationTest
2.assignable:类过滤器,该过滤器直接指定一个java类
3.regex,正则表达式过滤器,指定过滤规则,使用如下
4.aspectJ:AspectJ过滤器,如org.example.*Service+
-->
<!--<context:include-filter type="regex" expression=".*Axe"/> -->
<context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/>
<context:exclude-filter type="regex" expression=".*TeacherConfig"/>
<context:exclude-filter type="assignable" expression="org.springframework.context.support.ResourceBundleMessageSource"/>
<context:exclude-filter type="regex" expression="com.home.model.C*"/>
</context:component-scan>
<!-- 启动@AspectJ支持 -->
<aop:aspectj-autoproxy/>
测试类:
package com.aspect.service.impl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ImplHelloTest {
public static void main(String[] args) throws Exception{
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
HelloImpl helloImpl=context.getBean("helloImpl",HelloImpl.class);
helloImpl.sayHello();
helloImpl.addUser("xieyongxue", "1234");
}
}
输出如下:
启动测试
模拟执行权限检查
执行Hello组件的sayHello()方法
结束测试后
执行Hello组件的addUser添加用户:xieyongxue
模拟方法结束后释放资源...
2.其他几个增强处理具体示例
1.before:前置通知(应用:各种校验)
在方法执行前执行,如果通知抛出异常,阻止方法运行
2.afterReturning:后置通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,通知无法执行
必须在方法执行后才执行,所以可以获得方法的返回值。
3.around:环绕通知(应用:十分强大,可以做任何事情) 【掌握】
方法执行前后分别执行,可以阻止方法的执行。要求必须手动的执行目标方法。
4.afterThrowing:抛出异常通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行
5.after:最终通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常
package com.aspect.service;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class LogAspect {
@AfterReturning(returning="rvt",pointcut="execution(* *.addUser(..))")
//声明rvt时指定的类型会限制目标方法必须返回指定类型的值或者咩有返回值
//此处将rvt的类型声明为Object,意味着对目标方法的返回值不做限制
public void log(int rvt){
System.out.println("获取目标方法返回值:"+rvt);
System.out.println("模拟记录日志功能...");
}
@AfterThrowing(throwing="ex",pointcut="execution(* *.addUser(..))")
public void throwMsg(Throwable ex){
System.out.println("目标方法抛出的异常为:"+ex);
System.out.println("模拟Advice对异常的修复....");
}
@After("execution(* *.addUser(..))")
public void release(){
System.out.println("模拟方法结束后释放资源...");
}
}
package com.aspect.service;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class TxAspect {
@Around("execution(* *.addPersons(..))")
public Object txProcess(ProceedingJoinPoint jp) throws java.lang.Throwable{
System.out.println("执行目标方法之前开始模式事务....");
//获取目标方法原始调用的参数
Object[]args=jp.getArgs();
if(args.length>0 && args!=null){
//修改目标方法调用参数的第一个参数
args[0]=(Integer)args[0]*2;
}
//以改变后的参数去执行目标方法,并保存目标方法执行后的参数
Object rvt=jp.proceed(args);
System.out.println("执行目标方法后,模拟结束事务。。。。");
//如果rvt的类型是Integer,将rvt改为它的平方,用于改变目标方法的返回值
if(rvt!=null && rvt instanceof Integer){
rvt=(Integer)rvt*(Integer)rvt;
}
return rvt;
}
}
package com.aspect.service.impl;
import org.springframework.stereotype.Component;
import com.aspect.service.Hello;
@Component
public class World implements Hello{
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("执行Hello组件的sayHello方法");
}
public void addUser(String name, String pass) {
// TODO Auto-generated method stub
System.out.println("执行Hello组件的addUser的方法");
if(name.length()<3){
throw new IllegalArgumentException("传入名称的参数长度过短");
}
}
public int addUser(int rvt){
System.out.println("执行带返回值的addUser方法:"+rvt);
if(rvt<10){
throw new IllegalArgumentException("传入的参数过小");
}
return rvt;
}
public int addPersons(int rvt){
System.out.println("执行带返回值的addPerson()方法:"+rvt);
return rvt;
}
}
测试类:
package com.aspect.service.impl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class WorldTest {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
World world=context.getBean("world",World.class);
world.addUser(20);
world.addUser("xieyongxue", "1234");
world.addPersons(10);
System.out.println("addPersons的返回值为:"+world.addPersons(10));
}
}
输出:
执行带返回值的addUser方法:20
获取目标方法返回值:20
模拟记录日志功能...
模拟方法结束后释放资源...
执行Hello组件的addUser的方法
模拟方法结束后释放资源...
执行目标方法之前开始模式事务....
执行带返回值的addPerson()方法:20
执行目标方法后,模拟结束事务。。。。
执行目标方法之前开始模式事务....
执行带返回值的addPerson()方法:20
执行目标方法后,模拟结束事务。。。。
addPersons的返回值为:400