AOP (Aspect Orient Programming)面向切面编程
Aspect:表示切面,给业务方法增加的功能。切面一般都是非业务功能,而且切面功能一般都是可以复用的。例如日志功能、事务功能、权限检查、参数检查、统计信息等。
Joinpoint:连接点
Pointcut:切入点(一组连接点),表切面执行的位置
target:目标对象,给哪个对象增加切面的功能,这个对象就是目标对象
Advice:切面的执行时间,在目标方法之前执行切面,还是在目标方法之后执行切面
**
使用Aspectj框架实现AOP
1.Advice注解;
Aspectj表示切面执行时间,用的是通知(Advice)注解:
@Before:前置通知
@AfterReturning::后置通知
@Around:环绕通知
@AfterThrowing:异常通知
@After:最终通知
2.PointCut;
语法表示:execution(访问权限 方法返回值 方法声明(参数) 异常类型 );
通配符:
“*” 0-多个任意字符;
“…” 用在方法参数中,表示任意多个参数
###用在包名后,表示当前包及其子包路径;
“+” 用在类名后,表示当前类及其子类
###用在接口后,表示当前接口及其实现类;
实现步骤:
1.新建maven项目;
2.修改pom.xml,添加依赖:spring-aspects(使用aspectj框架的功能)
3.创建业务接口和实现类;
4.创建一个切面类
- 在类的上面加入@Aspect
- 在类中定义方法,方法表示切面的功能。在方法的上面加入Aspect框架中的通知注解,如@Before(value = "切入点表达式“)
@Aspect
public class MyAspect {
@Before(value = "execution(void org.example.service.SomeServiceImpl.doSome(String,int))")
public void MyBefore(){
System.out.println("前置通知");
}
}
前置通知方法的定义:
1)方法是public void,名称自定义
2)方法可以有参数,如果有是JoinPoint,也可以没有
JoinPont参数的作用:
表示正在执行的业务方法,使用要求必须是参数列表的第一个,作用是获取方法执行时的信息,如方法名称,方法的参数集合
@Aspect
public class MyAspect {
@Before(value = "execution(void org.example.service.SomeServiceImpl.doSome(String,int))")
public void MyBefore(JoinPoint jp){
System.out.println("获取目标方法的定义"+jp.getSignature());
System.out.println("获取目标方法的名称"+jp.getSignature().getClass());
System.out.println("前置通知");
}
}
5.创建spring配置文件
- 1)声明目标对象
- 2)声明切面类对象
- 3)声明自动代理生成器
<!-- 创建目标对象-->
<bean id="someService" class="org.example.service.SomeServiceImpl"/>
<!-- 创建切面类对象-->
<bean id="myAspect" class="org.example.handle.MyAspect"/>
<!-- 创建自动代理生成器-->
<aop:aspectj-autoproxy/>
6.创建测试类,测试目标方法执行时,增加切面的功能
public class AppTest {
@Test
public void test01() {
String config = "bean.xml";
ApplicationContext cat = new ClassPathXmlApplicationContext(config);
SomeService service = (SomeService)cat.getBean("someService");
service.doSome("lisi",22);
}
}
@AfterReturning:后置通知
@Aspect
public class MyAspect {
// @AfterReturning:属性value,returning(
// 自定义的变量,表示目标方法的返回值,自定义变量名必须和通知方法的形参名一样)
// 特点:能获取到目标方法的执行结果
@AfterReturning(value = "execution(* org.example.service.SomeServiceImpl.doOther(String,int))",returning = "res")
public void MyAfter(Object res){
System.out.println("后置通知");
}
}
@Around :环绕通知
@Aspect
public class MyAspect {
// @Around:属性value,
// 返回值:object,表示调用目标方法希望得到执行结果(不一定是目标方法自己的返回值)
// 参数:ProceedingJoinPoint(作用是执行目标方法)
// public interface ProceedingJoinPoint extends JoinPoint{}
// 特点:1)在目标方法的前和后都能增强功能
// 2)控制目标方法是否执行
// 3)修改目标方法的执行结果
@Around(value = "execution(* org.example.service.SomeServiceImpl.doFirst(String))")
public Object MyAround(ProceedingJoinPoint pj) throws Throwable {
System.out.println("环绕通知");
Object o = pj.proceed();//执行目标方法
return o;//返回目标方法的返回值
}
}
执行结果:
1)环绕通知
2)执行doFirst(目标方法)
3)ab(目标方法的返回值)
@AfterThrowing:异常通知
@Aspect
public class MyAspect {
//AfterThrowing
// 方法没有返回值,方法的参数是Exception
// 属性:value,throwing表示目标方法抛出的异常。变量名必须和通知方法的形参名一样。
// 特点:1)在目标方法抛出异常后执行。没有异常不执行
// 2)能获取目标方法的异常信息
// 3)不是异常处理程序,可以得到发生异常的通知,可以发送邮件,短信通知开发人员,可以看作是目标方法的监控程序。
@AfterThrowing(value = "execution(* org.example.service.SomeServiceImpl.doSecond(String))",throwing = "ex")
public void MyThrowing(Exception ex) {
System.out.println("异常通知");
}
}
@After:最终通知
@After
// 属性:value
// 特点:1)在目标方法执行之后执行的
// 2)总会被执行
// 3)可以用来做程序最后的收尾工作,如:清除临时数据,变量,清理内存
@After(value = "execution(* org.example.service.SomeServiceImpl.doThird(String))")
public void myAfter(){
System.out.println("执行after");
}
@Pointcut
// Pointcut:定义和管理切入点,不是通知注解
// 属性:value
// 位置:在一个自定义方法的上面。这个方法可以看作切入表达式的别名
@After(value = "execution(* org.example.service.SomeServiceImpl.doThird(..))")
public void myAfter(){
System.out.println("执行after");
}
@Before(value = "execution(* org.example.service.SomeServiceImpl.doThird(..))")
public void myBefore(){
System.out.println("前置通知");
}
@Pointcut(value= "execution(* org.example.service.SomeServiceImpl.doThird(..))")
public void mapt(){
// 无需代码
}
AOP总结:
AOP是一种动态的技术思想,目的是实现业务功能的解耦合。业务功能是独立的模块,其他功能也是独立的模块。例如事务功能,日志等。让这些事务,日志功能是可以被复用的。
当目标方法需要一些功能时,可以在不修改,不能修改代码的情况下使用AOP技术在程序执行期间生成代理对象,通过代理对象执行业务方法,同时增加功能。