AOP:中文名称面向切面编程 (Aspect Oriented Programming)
正常程序执行流程都是纵向执行流程
面向切面编程,在原有纵向执行流程中添加横切面
不需要修改原有程序代码 高扩展性 原有功能相当于释放了部分逻辑.让职责更加明确
面向切面编程是什么?
在程序原有纵向执行流程中,针对某一个或某一些方法添加通 知,形成横切面过程就叫做面向切面编程.
常用概念
原有功能: 切点, pointcut
前置通知: 在切点之前执行的功能. before advice
后置通知: 在切点之后执行的功能,after advice
如果切点执行过程中出现异常,会触发异常通知.throws advice
所有功能总称叫做切面.
织入: 把切面嵌入到原有功能的过程叫做织入
开始 导入jar包
编写切入点
public class Myadvice {
public void mybefore(){
System.out.println("前置" );
}
public void myafterReturing(){
System.out.println("返回后置");
}
public void myafter(){
System.out.println("后置");
}
public void mythrow(){
System.out.println("异常");
}
public Object myarround(ProceedingJoinPoint p) throws Throwable{
System.out.println("环绕-前置");
Object result = p.proceed();
System.out.println("环绕后置");
return result;
}
}
功能类
public class Demo {
public void demo(){
System.out.println("demo运行了。");
}
}
spring配置文件
<!--配置demo类-->
<bean id="demo" class="com.xt.aop.Demo"></bean>
<!-- 切面类-->
<bean id="myAdvice" class="com.xt.aop.Myadvice"></bean>
<!-- 配置切入点 -->
<aop:config>
<!-- 切入点-->
<aop:pointcut id="myPoint" expression="execution(* com.xt.aop.Demo.*(..) )"></aop:pointcut>
<aop:aspect ref="myAdvice">
<!--前置通知-->
<aop:before method="mybefore" pointcut-ref="myPoint"></aop:before>
<!-- 后置通知-->
<aop:after method="myafter" pointcut-ref="myPoint"/>
<!-- 返回后通知 -->
<aop:after-returning method="myafterReturing" pointcut-ref="myPoint"/>
<!-- 异常通知 -->
<aop:after-throwing method="mythrow" pointcut-ref="myPoint"/>
<!-- -环绕通知 -->
<aop:around method="myarround" pointcut-ref="myPoint"/>
</aop:aspect>
</aop:config>
execution 是切入点表达式,表示要在哪个类中哪个方法中进行切入,可以跟随自己项目进行配置
出自官方文档:execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
throws-pattern?)
modifiers-pattern 表示拦截方法的访问修饰符
ret-type-pattern 返回类型
declaring-type-pattern 拦截方法所在类
name-pattern(param-pattern) 拦截方法(以及方法参数列表)
throws-pattern 方法异常
运行效果如下
Spring生成代理对象的过程
1.创建容器对象时,根据切入点表达式拦截的类,生成代理对象
2.如果目标对象有实现接口,使用JDK代理
3.如果目标对象没有实现接口,使用CGLIB代理
4.从容器中获取代理后的对象
5.执行代理对象的方法,在运行时,动态植入切面类中的通知方法
二、基于注解实现AOP编程
功能类
@Component("demo")//加入到IOC容器
public class Demo implements DemoI {
public void demo(){
System.out.println("demo运行了。");
}
}
切面类
@Component//加入IOC容器
@Aspect//指定为切面类
public class Myadvice {
//标识切入点
@Pointcut("execution(* com.xt.aopano.aop.Demo.*(..))")
public void point(){}
//@Before("execution(* com.xt.aopano.aop.Demo.*(..))")
@Before("point()")
public void mybefore(){
System.out.println("前置" );
}
@AfterReturning("execution (* com.xt.aopano.aop.Demo.*(..) )")
public void myafterReturing(){
System.out.println("返回后置");
}
@After("execution(* com.xt.aopano.aop.Demo.*(..) )")
public void myafter(){
System.out.println("后置");
}
@AfterThrowing("execution(* com.xt.aopano.aop.Demo.*(..) )")
public void mythrow(){
System.out.println("异常");
}
@Around("execution(* com.xt.aopano.aop.Demo.*(..) )")
public Object myarround(ProceedingJoinPoint p) throws Throwable{
System.out.println("环绕-前置");
Object result = p.proceed();//执行目标方法
System.out.println("环绕后置");
return result;
}
}
spring配置文件
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.xt.aopano.aop"></context:component-scan>
<!-- 开启aop注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>