织梦做网站简单吗,wordpress图片放七牛云,好的室内设计网站,广告关键词有哪些文章目录 一、基于XML的AOP1.1、打印日志案例1.1.1、beans.xml中添加aop的约束1.1.2、定义Bean 1.2、定义记录日志的类【切面】1.3、导入AOP的依赖1.4、主配置文件中配置AOP1.5、测试1.6、切入点表达式1.6.1、访问修饰符可以省略1.6.2、返回值可以使用通配符#xff0c;表示任… 文章目录 一、基于XML的AOP1.1、打印日志案例1.1.1、beans.xml中添加aop的约束1.1.2、定义Bean 1.2、定义记录日志的类【切面】1.3、导入AOP的依赖1.4、主配置文件中配置AOP1.5、测试1.6、切入点表达式1.6.1、访问修饰符可以省略1.6.2、返回值可以使用通配符表示任意返回值1.6.3、包名可以使用通配符表示任意包。有几级包就几个*1.6.4、类名也可以用*1.6.5、方法也可以用*1.6.6、参数列表1.6.7、全通配符写法1.6.8、使用最多的写法 1.7、通知类型的使用1.7.1、在日志类中新增通知方法1.7.2、配置AOP1.7.3、测试 1.8、切入点表达式改进1.8.1、方式一1.8.2、方式二 1.9、环绕通知1.9.1、在日志记录类中新增环绕通知1.9.2、AOP配置环绕通知1.9.3、测试11.9.4、解决 好书推荐 一、基于XML的AOP
1.1、打印日志案例
1.1.1、beans.xml中添加aop的约束
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd
/beans1.1.2、定义Bean
package cn.bdqn.domain;
public class User {}package cn.bdqn.service;
public interface UserService {// 保存用户public void save(User user);// 根据id查询用户public User queryById(Integer id);// 查询全部用户public ListUser queryAll();
}package cn.bdqn.service;
public class UserServiceImpl implements UserService{// 保存用户public void save(User user){}// 根据id查询用户public User queryById(Integer id){return new User();}// 查询全部用户public ListUser queryAll(){return new ArrayListUser();}
}1.2、定义记录日志的类【切面】
package cn.bdqn.advice;// 定义记录日志的类,这个类就封装了我们所有的公共的代码
public class Logger {// 该方法的作用是在切入点方法执行之前执行public void beforePrintLog(){System.out.println(开始打印日志啦);}
}1.3、导入AOP的依赖
dependencygroupIdorg.aspectj/groupIdartifactIdaspectjweaver/artifactIdversion1.9.4/version
/dependency1.4、主配置文件中配置AOP
beans!-- 1、注册UserServiceImpl这个Bean --bean iduserService classcn.bdqn.service.UserServiceImpl/!-- 2、以下操作都是Spring基于XML的AOP配置步骤2.1 把通知/增强Bean也需要注册到Spring容器中2.2 使用aop:config/标签来去声明开始AOP的配置了2.3 使用aop:aspect/标签来去表示开始配置切面了可以想一下既然要配置切面那切面就是切入点和通知的结合所以肯定需要配置切入点和通知这两部分id属性是给切面提供一个唯一标识ref属性是指定通知类bean的Id。2.4 在aop:aspect/标签的内部使用对应标签来配置通知的类型前置通知/后置通知/异常通知/最终通知需求:beforePrintLog方法在切入点方法执行之前之前所以是前置通知前置通知aop:before/method属性用于指定Logger类中哪个方法是前置通知pointcut属性用于指定切入点表达式该表达式的含义指的是对业务层中哪些方法增强3、切入点表达式的写法关键字execution(表达式)表达式访问修饰符 方法返回值 包名1.包名2...类名.方法名(参数列表)需求我现在就想对UserServiceImpl类中的queryAll方法进行拦截public java.util.List cn.bdqn.service.UserServiceImpl.queryAll()--!-- 2.1 把通知/增强Bean也需要注册到Spring容器中 --bean idlogger classcn.bdqn.advice.Logger/!-- 2.2 使用此标签来去声明开始AOP的配置了--aop:config!--配置切面 --aop:aspect idloggerAdvice reflogger!-- 配置通知的类型并且建立增强方法和切入点方法的关联--aop:before methodbeforePrintLog pointcutexecution(public java.util.List cn.bdqn.service.UserServiceImpl.queryAll())//aop:aspect/aop:config
/beans1.5、测试 Test
public void testUserServiceImpl() throws Exception{ApplicationContext ac new ClassPathXmlApplicationContext(beans.xml);UserService userService (UserService) ac.getBean(userService);userService.queryAll();
}1.6、切入点表达式
问题我们上面的案例经过测试发现确实在调用业务方法之前增加了日志功能但是问题是仅仅能针对某一个业务方法进行增强而我们的业务方法又有可能有很多所以显然一个一个的去配置很麻烦如何更加灵活的去配置呢这个就需要使用到切入点表达式
语法execution(表达式)
访问修饰符 方法返回值 包名1.包名2...类名.方法名(参数列表)1.6.1、访问修饰符可以省略
// 完整写法
public java.util.List cn.bdqn.service.UserServiceImpl.queryAll())// 标准写法
java.util.List cn.bdqn.service.UserServiceImpl.queryAll())1.6.2、返回值可以使用通配符表示任意返回值
* cn.bdqn.service.UserServiceImpl.queryAll())1.6.3、包名可以使用通配符表示任意包。有几级包就几个*
* *.*.*.UserServiceImpl.queryAll())但是对于包来说连续的写3个*显然也是麻烦的那么可以使用“…”表示当前包及其子包。
// 表示的是任意包下的只要有UserServiceImpl类都会对queryAll方法进行增强
* *..UserServiceImpl.queryAll())1.6.4、类名也可以用*
* *..*.queryAll()1.6.5、方法也可以用*
* *..*.*()1.6.6、参数列表
写法1、可以直接写数据类型基本类型直接写名称 int、double引用类型写包名.类名的方式 java.lang.String、java.util.List
写法2、可以使用通配符表示任意类型前提是必须要有参数。写法3、使用..可以使用..表示有无参数均可如果有参数则表示的可以是任意类型 1.6.7、全通配符写法 * *..*.*(..)1.6.8、使用最多的写法
实际中的写法切到业务层实现类下的所有方法。即
* com.bdqn.service.impl.*.*(..)1.7、通知类型的使用
1.7.1、在日志类中新增通知方法
// 定义记录日志的类,这个类就封装了我们所有的公共的代码
public class Logger {// 该方法的作用是在切入点方法执行之前执行public void beforePrintLog(){System.out.println(前置通知(beforePrintLog)开始打印日志啦);}// 该方法的作用是在切入点方法执行之后执行public void afterReturningPrintLog(){System.out.println(后置通知(afterReturningPrintLog)业务方法执行完了日志打印);}// 该方法的作用是在切入点方法执行出错后执行public void afterThrowingPrintLog(){System.out.println(异常通知(afterThrowingPrintLog)业务方法出现异常了日志打印);}// 该方法的作用是在切入点方法执行之后不管有没有错误都最终要执行public void afterPrintLog(){System.out.println(最终通知(afterPrintLog)业务方法不管有没有异常了日志打印);}
}1.7.2、配置AOP
beans!-- 2.1 把通知/增强Bean也需要注册到Spring容器中 --bean idlogger classcn.bdqn.advice.Logger/!-- 2.2 使用此标签来去声明开始AOP的配置了--aop:config!--配置切面 --aop:aspect idloggerAdvice reflogger!-- 配置前置通知在切入点方法执行之前执行--aop:before methodbeforePrintLog pointcutexecution(* cn.bdqn.service.UserServiceImpl.queryAll())/!-- 后置通知在切入点方法正常执行之后值。它和异常通知永远只能执行一个--aop:after-returning methodafterReturningPrintLog pointcutexecution(* cn.bdqn.service.UserServiceImpl.queryAll())/!--配置异常通知在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个--aop:after-throwing methodafterThrowingPrintLog pointcutexecution(* cn.bdqn.service.UserServiceImpl.queryAll())/!--配置最终通知无论切入点方法是否正常执行它都会在其后面执行--aop:after methodafterPrintLogpointcutexecution(* cn.bdqn.service.UserServiceImpl.queryAll())//aop:aspect/aop:config
/beans1.7.3、测试
Test
public void testUserServiceImpl() throws Exception{ApplicationContext ac new ClassPathXmlApplicationContext(beans.xml);UserService userService (UserService) ac.getBean(userService);userService.queryAll();
}
/***前置通知(beforePrintLog)开始打印日志啦查询全部用户执行啦后置通知(afterReturningPrintLog)业务方法执行完了日志打印最终通知(afterPrintLog)业务方法不管有没有异常了日志打印
**/1.8、切入点表达式改进
通过11.7可以发现我们在配置文件中配置了四种通知类型其中的pointcut配置的是切入点表达式发现是一模一样的那么有没有一种改进写法呢可以将表达式抽取出来将来可以引用。
1.8.1、方式一
beans!-- 1、注册UserServiceImpl这个Bean --bean iduserService classcn.bdqn.service.UserServiceImpl/!-- 2、以下操作都是Spring基于XML的AOP配置步骤--!-- 2.1 把通知/增强Bean也需要注册到Spring容器中 --bean idlogger classcn.bdqn.advice.Logger/!-- 2.2 使用此标签来去声明开始AOP的配置了--aop:config!--配置切面 --aop:aspect idloggerAdvice reflogger!--配置切入点表达式id属性用于指定切入点表达式的唯一标识。expression属性用于指定表达式内容此标签写在aop:aspect标签内部只能当前切面使用。--aop:pointcut idloggerPt expressionexecution(* cn.bdqn.service.UserServiceImpl.queryAll())/!-- 配置前置通知在切入点方法执行之前执行--aop:before methodbeforePrintLog pointcut-refloggerPt/!-- 后置通知在切入点方法正常执行之后值。它和异常通知永远只能执行一个--aop:after-returning methodafterReturningPrintLog pointcut-refloggerPt/!--配置异常通知在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个--aop:after-throwing methodafterThrowingPrintLog pointcut-refloggerPt/!--配置最终通知无论切入点方法是否正常执行它都会在其后面执行--aop:after methodafterPrintLog pointcut-refloggerPt//aop:aspect/aop:config
/beans1.8.2、方式二
对于方式一我们将aop:pointcut标签写在了aop:aspect里面这样的话这切入点表达式只能被当前的切面使用而如果其他切面想使用就使用不到了所以我们可以把这个切入点表示再定义到外面。
beansbean iduserService classcn.bdqn.service.UserServiceImpl/!-- 2、以下操作都是Spring基于XML的AOP配置步骤--!-- 2.1 把通知/增强Bean也需要注册到Spring容器中 --bean idlogger classcn.bdqn.advice.Logger/!-- 2.2 使用此标签来去声明开始AOP的配置了--aop:config!--配置切入点表达式id属性用于指定切入点表达式的唯一标识。expression属性用于指定表达式内容此标签写在aop:aspect标签外面那么所有的切面都可以使用。--aop:pointcut idloggerPt expressionexecution(* cn.bdqn.service.UserServiceImpl.queryAll())/!--配置切面 --aop:aspect idloggerAdvice reflogger!-- 配置前置通知在切入点方法执行之前执行--aop:before methodbeforePrintLog pointcut-refloggerPt/!-- 后置通知在切入点方法正常执行之后值。它和异常通知永远只能执行一个--aop:after-returning methodafterReturningPrintLog pointcut-refloggerPt/!--配置异常通知在切入点方法执行产生异常之后执行。它和后置通知永远只能执行一个--aop:after-throwing methodafterThrowingPrintLog pointcut-refloggerPt/!--配置最终通知无论切入点方法是否正常执行它都会在其后面执行--aop:after methodafterPrintLog pointcut-refloggerPt//aop:aspect/aop:config
/beans1.9、环绕通知
1.9.1、在日志记录类中新增环绕通知
public class Logger {// 环绕通知public void aroundPrintLog(){System.out.println(环绕通知....aroundPrintLog.....);}
}1.9.2、AOP配置环绕通知
beans!-- 1、注册UserServiceImpl这个Bean --bean iduserService classcn.bdqn.service.UserServiceImpl/!-- 2、以下操作都是Spring基于XML的AOP配置步骤--!-- 2.1 把通知/增强Bean也需要注册到Spring容器中 --bean idlogger classcn.bdqn.advice.Logger/!-- 2.2 使用此标签来去声明开始AOP的配置了--aop:config!-- 配置切入点表达式 --aop:pointcut idloggerPt expressionexecution(* cn.bdqn.service.UserServiceImpl.queryAll())/!--配置切面 --aop:aspect idloggerAdvice reflogger!-- 环绕通知--aop:around methodaroundPrintLog pointcut-refloggerPt//aop:aspect/aop:config
/beans1.9.3、测试1
Test
public void testUserServiceImpl() throws Exception{ApplicationContext ac new ClassPathXmlApplicationContext(beans.xml);UserService userService (UserService) ac.getBean(userService);userService.queryAll();
}
/**环绕通知....aroundPrintLog.....发现仅仅打印了环绕通知的代码。当我们配置了环绕通知之后切入点方法没有执行而通知方法执行了
*/1.9.4、解决
Spring框架为我们提供了一个接口ProceedingJoinPoint。该接口有一个方法proceed()此方法就相当于明确调用切入点方法。该接口可以作为环绕通知的方法参数在程序执行时spring框架会为我们提供该接口的实现类供我们使用。
public class Logger {// 环绕通知public Object aroundPrintLog(ProceedingJoinPoint pjp){Object result null;try{Object[] args pjp.getArgs();System.out.println(pjp.getSignature().getName());System.out.println(前置);result pjp.proceed(args);System.out.println(后置);return result;}catch (Throwable t){System.out.println(异常);throw new RuntimeException(t);}finally {System.out.println(最终);}}
}
/**环绕通知它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
*/好书推荐 《深入浅出Spring Boot 3.x》 作者简介 杨开振——长期从事Java开发工作拥有近十年的Java开发经验目前就职于一家互联网金融公司担任互联网软件开发职位。 IT技术的狂热爱好者热衷于Java互联网方向的软件技术开发与研究。熟练掌握Java基础、软件开发设计模式和数据库相关知识对Spring、MyBatis等主流Java开源框架有深入研究。 购书链接点此进入