cati mls round -i one 空指针 继承 context
AOP
AOP(Aspect Oriented Programming),即面向切面编程,可以说是 OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP 引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过 OOP 允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在 OOP 设计中,它导致了大量代码的重复,而不利于各个模块的重用。
AOP 技术恰恰相反,它利用一种称为 "横切" 的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为 "Aspect",即切面。所谓 "切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
使用 "横切" 技术,AOP 把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
基于 Spring 的 AOP 简单实现
1、通过配置文件实现 AOP
首先需要额外上网下载两个 jar 包:
① aspectjrt.jar② aspectjweaver.jar
先定义一个接口 IHelloWorld:
- 1 public interface IHelloWorld {
- 2 void printHelloWorld(String name);
- 3
- }
定义一个实现类 HelloWorld
- 1 public classHelloWorldimplements IHelloWorld {
- 2
- 3 @Override
- 4 public void printHelloWorld(String name) {
- 5System.out.println("Print HelloWorld :" + name);
- 6 }
- 7}
实现了两个切面(一个日志切面和一个时间切面)
- 1 public class LogAspect {
- 2 public void beforeLog(JoinPoint joinPoint) {
- 3 System.out.println("log before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
- 4
- }
- 5 public void afterLog(JoinPoint joinPoint) {
- 6 System.out.println("log after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
- 7
- }
- 8
- }
- 1 public class TimeAspect {
- 2 public void beforeTime(JoinPoint joinPoint) {
- 3 System.out.println("time before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
- 4
- }
- 5 public void afterTime(JoinPoint joinPoint) {
- 6 System.out.println("time after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
- 7
- }
- 8
- }
定义一个配置文件
- 1 <?xml version="1.0" encoding="UTF-8"?>
- 2 <beans xmlns="http://www.springframework.org/schema/beans"
- 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- 4 xmlns:context="http://www.springframework.org/schema/context"
- 5 xmlns:aop="http://www.springframework.org/schema/aop"
- 6 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">
- 7
- 8 <!-- 核心业务Bean -->
- 9 <bean id="helloworld" class="com.hzg.HelloWorld"></bean>
- 10
- 11 <!-- 切面Bean(日志切面) -->
- 12 <bean id="logAspect" class="com.hzg.LogAspect"></bean>
- 13
- 14 <!-- 切面Bean(时间切面) -->
- 15 <bean id="timeAspect" class="com.hzg.TimeAspect"></bean>
- 16
- 17 <!-- AOP配置 -->
- 18 <aop:config>
- 19 <!-- 配置切点 -->
- 20 <aop:pointcut id="pointcut" expression="execution(* com.hzg.IHelloWorld.*(..))"></aop:pointcut>
- 21 <!-- 配置切面(日志切面)切面的优先级需要通过order定义 -->
- 22 <aop:aspect id="log" ref="logAspect"order="1">
- 23 <!-- 配置通知(前置通知、后置通知、返回通知、异常通知、环绕通知) -->
- 24 <aop:before method="beforeLog" pointcut-ref="pointcut"></aop:before>
- 25 <aop:after method="afterLog" pointcut-ref="pointcut"></aop:after>
- 26 </aop:aspect>
- 27 <!-- 配置切面(时间切面)切面的优先级需要通过order定义 -->
- 28 <aop:aspect id="time" ref="timeAspect"order="2">
- 29 <!-- 配置通知(前置通知、后置通知、后置返回通知、异常通知、环绕通知) -->
- 30 <aop:before method="beforeTime" pointcut-ref="pointcut"></aop:before>
- 31 <aop:after method="afterTime" pointcut-ref="pointcut"></aop:after>
- 32 </aop:aspect>
- 33 </aop:config>
- 34
- 35 </beans>
定义 Main 主方法
- 1 public static void main(String[] args) {
- 2 //由于ApplicationContext没有close方法,所以要使用它下面接口ConfigurableApplicationContext
- 3 ApplicationContext ctx = new ClassPathXmlApplicationContext("configaop.xml");
- 4 IHelloWorld helloworld = (IHelloWorld) ctx.getBean("helloworld");
- 5 helloworld.printHelloWorld("gangge");
- 6
- }
输出结果:
- log before method printHelloWorld参数 :[gangge]
- time before method printHelloWorld参数 :[gangge]
- Print HelloWorld :gangge
- time after method printHelloWorld参数 :[gangge]
- log after method printHelloWorld参数 :[gangge]
2、通过注解实现 AOP
实现配置文件方式同样的功能
先定义一个接口文件(没区别)
- 1 public interface IHelloWorld {
- 2 void printHelloWorld(String name);
- 3
- }
定义实现类(区别:[email protected])
- 1 @Component
- 2 public classHelloWorldimplements IHelloWorld {
- 3
- 4 @Override
- 5 public void printHelloWorld(String name) {
- 6System.out.println("Print HelloWorld :" + name);
- 7 }
- 8}
定义两个切面(一个日志切面和一个时间切面 区别:[email protected]@[email protected])
- 1 @Component
- 2 @Aspect
- 3@Order(1)
- 4 public class LogAspect {
- 5 public void beforeLog(JoinPoint joinPoint){
- 6System.out.println("log before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
- 7 }
- 8 public void afterLog(JoinPoint joinPoint){
- 9System.out.println("log after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
- 10 }
- 11}
- 1 @Component
- 2 @Aspect
- 3@Order(2)
- 4 public class TimeAspect {
- 5@Before("execution(* com.hzg.HelloWorld.*(..))")
- 6 public void beforeTime(JoinPoint joinPoint){
- 7System.out.println("time before method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
- 8 }
- 9@After("execution(* com.hzg.HelloWorld.*(..))")
- 10 public void afterTime(JoinPoint joinPoint){
- 11System.out.println("time after method " + joinPoint.getSignature().getName() + "参数 :" + Arrays.asList(joinPoint.getArgs()));
- 12 }
- 13}
定义配置文件(区别:Spring 自动扫描包和 aop 自动代理)
- 1 <?xml version="1.0" encoding="UTF-8"?>
- 2 <beans xmlns="http://www.springframework.org/schema/beans"
- 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- 4 xmlns:context="http://www.springframework.org/schema/context"
- 5 xmlns:aop="http://www.springframework.org/schema/aop"
- 6 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">
- 7
- 8 <context:component-scan base-package="com.hzg"></context:component-scan>
- 9 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 10
- 11 </beans>
定义 Main 主方法(无区别)
- 1 public static void main(String[] args) {
- 2 //由于ApplicationContext没有close方法,所以要使用它下面接口ConfigurableApplicationContext
- 3 ApplicationContext ctx = new ClassPathXmlApplicationContext("configaop.xml");
- 4 IHelloWorld helloworld = (IHelloWorld) ctx.getBean("helloworld");
- 5 helloworld.printHelloWorld("gangge");
- 6
- }
输出结果和配置文件一样
五种通知:
1、前置通知
上面已经有了,不再说明
2、后置通知
上面已经有了,不再说明
3、返回通知
- 1
- /**
- 2 * 返回通知: 方法正常执行完后调用,如果有异常,则不调用
- 3 * 可以访问到方法的返回值
- 4 * @param joinPoint
- 5 * @param result 方法的返回值
- 6 */
- 7@AfterReturning(value = "execution(* com.hzg.*(..))", returning = "result") 8 public void afterReturning(JoinPoint joinPoint, Object result) {
- 9 //方法名
- 10 String methodName = joinPoint.getSignature().getName();
- 11 System.out.println("method " + methodName + " end:" + result);
- 12
- }
4、异常通知
- 1
- /**
- 2 * 异常通知: 当方法出现异常时
- 3 * 可以指定出现哪些异常时才执行: 如何指定?通过入参指定,如:
- 4 * 如果入参为NullPointException ex,那么只有在发生空指针异常时才执行
- 5 * @param joinPoint
- 6 * @param ex
- 7 */
- 8@AfterThrowing(value = "execution(* com.hzg.*(..))", throwing = "ex") 9 public void afterThrowing(JoinPoint joinPoint, Exception ex) {
- 10 //方法名
- 11 String methodName = joinPoint.getSignature().getName();
- 12 System.out.println("method " + methodName + " occurs:" + ex);
- 13
- }
5、环绕通知
环绕通知类似于动态代理的全过程,可以使用环绕通知实现前置通知,后置通知,返回通知,异常通知的功能,十分强大,但并不常用
- 1
- /**
- 2 * 环绕通知需要携带ProceedingJoinPoint类型的参数
- 3 * 环绕通知类似于动态代理的全过程: ProceedingJoinPoint这个类型的参数可以决定是否执行目标方法
- 4 * 且环绕通知必须有返回值,返回值即为目标方法的返回值
- 5 * @param pjd
- 6 */
- 7@Around("execution(* com.hzg.*(..))") 8 public Object around(ProceedingJoinPoint pjd) {
- 9 Object result = null;
- 10 String methodName = pjd.getSignature().getName();
- 11 12
- try {
- 13 //前置通知
- 14 System.out.println("method:" + methodName + " begins with " + Arrays.asList(pjd.getArgs()));
- 15 //执行目标方法
- 16 result = pjd.proceed();
- 17 //返回通知
- 18 System.out.println("method:" + methodName + " end with " + result);
- 19
- } catch(Throwable e) {
- 20 // 异常通知
- 21 System.out.println("method:" + methodName + " occurs exception " + e);
- 22
- }
- 23 //后置通知
- 24 System.out.println("method ends");
- 25
- return result;
- 26
- }
-------------------------------------------------------------------------------------------------------------------------
跟着刚哥学习 Spring 框架 --AOP(五)
来源: http://www.bubuko.com/infodetail-2057011.html