AOP的简介
- AOP(Aspect Oriented Programing)面向切面编程,一种编程范式,隶属于软工范畴,指导开发者如何组织程序结构
AOP弥补了OOP的不足,基于OOP基础之上进行横向开发
- uOOP规定程序开发以类为主体模型,一切围绕对象进行,完成某个任务先构建模型
- uAOP程序开发主要关注基于OOP开发中的共性功能,一切围绕共性功能进行,完成某个任务先构建可能遇到的所有共性功能(当所有功能都开发出来也就没有共性与非共性之分)
AOP作用
- 伴随着AOP时代的降临,可以从各个行业的标准化、规范化开始入手,一步一步将所有共性功能逐一开发完毕,最终以功能组合来完成个别业务模块乃至整体业务系统的开发
- 目标:将软件开发由手工制作走向半自动化/全自动化阶段,实现“插拔式组件体系结构”搭建
AOP优势
- 提高代码的可重用性
- 业务代码编码更简洁
- 业务代码维护更高效
业务功能扩展更便捷
AOP的相关概念
- Joinpoint(连接点):就是方法
- Pointcut(切入点):就是挖掉共性功能的方法
- Advice(通知):就是共性功能,最终以一个方法的形式呈现
- Aspect(切面):就是共性功能与挖的位置的对应关系
- Target(目标对象):就是挖掉功能的方法对应的类产生的对象,这种对象是无法直接完成最终工作的
- Weaving(织入):就是将挖掉的功能回填的动态过程
- Proxy(代理):目标对象无法直接完成工作,需要对其进行功能回填,通过创建原始对象的代理对象实现
- Introduction(引入/引介) :就是对原始对象无中生有的添加成员变量或成员方法
AOP开发过程
开发阶段(开发者完成)
- 正常的制作程序
- 将非共性功能开发到对应的目标对象类中,并制作成切入点方法
- 将共性功能独立开发出来,制作成通知
- 在配置文件中,声明切入点
- 在配置文件中,声明切入点与通知间的关系(含通知类型),即切面
运行阶段(AOP完成)
- Spring容器加载配置文件,监控所有配置的切入点方法的执行
- 当监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置将通知对应的功能织入,完成完整的代码逻辑并运行
AOP的通知类型5种
- 前置通知:原始方法执行前执行,如果通知中抛出异常,阻止原始方法运行
应用:数据校验 格式:
<aop:aspect ref="adviceId"> <aop:before method="methodName" pointcut="……"/> </aop:aspect>- 说明:一个aop:aspect标签中可以配置多个aop:before标签
基本属性:
- method :在通知类中设置当前通知类别对应的方法
- pointcut :设置当前通知对应的切入点表达式,与pointcut-ref属性冲突
- pointcut-ref :设置当前通知对应的切入点id,与pointcut属性冲突
- 后置通知:原始方法执行后执行,无论原始方法中是否出现异常,都将执行通知
应用:现场清理 格式:
<aop:aspect ref="adviceId"> <aop:after method="methodName" pointcut="……"/> </aop:aspect>- 说明:一个aop:aspect标签中可以配置多个aop:after标签
返回后通知:原始方法正常执行完毕并返回结果后执行,如果原始方法中抛出异常,无法执行
应用:返回- 格式:<aop:aspect ref="adviceId"> <aop:after-returning method="methodName" pointcut="……"/> </aop:aspect>- 说明:一个aop:aspect标签中可以配置多个aop:after-returning标签
值相关数据处理 - 抛出异常后通知:原始方法抛出异常后执行,如果原始方法没有抛出异常,无法执行
应用:对原始方法中出现的异常信息进行处理 格式:
<aop:aspect ref="adviceId"> <aop:after-throwing method="methodName" pointcut="……"/> </aop:aspect>- 说明:一个aop:aspect标签中可以配置多个aop:after-throwing标签
环绕通知:在原始方法执行前后均有对应执行执行,还可以阻止原始方法的执行
应用:十分强大,可以做任何事情- 格式:
<aop:aspect ref="adviceId"> <aop:around method="methodName" pointcut="……"/> </aop:aspect>- 说明:一个aop:aspect标签中可以配置多个aop:around标签
环绕通知的开发方式 环绕通知是在原始方法的前后添加功能,在环绕通知中,存在对原始方法的显式调用
public Object around(ProceedingJoinPoint pjp) throws Throwable { Object ret = pjp.proceed(); return ret; }环绕通知方法相关说明:
- 方法须设定Object类型的返回值,否则会拦截原始方法的返回。如果原始方法返回值类型为void,通知方 也可以设定返回值类型为void,最终返回null
- 方法需在第一个参数位置设定ProceedingJoinPoint对象,通过该对象调用proceed()方法,实现对原始方法的调用。如省略该参数,原始方法将无法执行
- 使用proceed()方法调用原始方法时,因无法预知原始方法运行过程中是否会出现异常,强制抛出Throwable对象,封装原始方法中可能出现的异常信息
AOP的入门案例
案例目录结构
接口和接口实现类编写
package com.limei.service;
public interface UserService {
public void save(int i,int m );
}
package com.limei.service.impl;
import com.limei.service.UserService;
public class UserServiceImpl implements UserService {
public void save(int i,int m) {
//0.将共性功能抽取出来
//System.out.println("共性功能");
System.out.println("user service running..."+i+","+m);
}
}
AOP的通知类
package com.limei.aop;
import org.aspectj.lang.JoinPoint;
public class AOPAdvice {
public void function(JoinPoint jp){
Object[] args = jp.getArgs ();
System.out.println("共性功能。。。"+args[0]);
}
public void before(int x,int y){
System.out.println ("before..."+x+","+y);
}
}
xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--3.开启AOP命名空间-->
<bean id="userService" class="com.limei.service.impl.UserServiceImpl"/>
<!--2.配置共性功能成功spring控制的资源-->
<bean id="myAdvice" class="com.limei.aop.AOPAdvice"/>
<!--4.配置AOP-->
<aop:config>
<!--5.配置切入点-->
<aop:pointcut id="pt" expression="execution(* *..*(..))"/><!--关键字(访问修饰符 返回值 包名.类名.方法名(参数) 异常名)-->
<!--6.配置切面(切入点与通知的关系)-->
<aop:aspect ref="myAdvice">
<!--7.配置具体的切入点对应通知中那个操作方法-->
<aop:before method="function" pointcut-ref="pt"/>
<aop:before method="before" pointcut="execution(* *..*(int,int))&&args(x,y)"></aop:before>
</aop:aspect>
</aop:config>
</beans>启动类
import com.limei.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext ( "applicationContext.xml" );
UserService userService = (UserService) ctx.getBean ( "userService" );
userService.save (666,777);
}
}
评论 (0)