(1)AOP概述
- AOP:面向切面编程,扩展功能不修改源代码实现
- AOP采取横向抽取机制,取代了传统的纵向继承体系重复性代码
(2)AOP底层原理
原始方法-------》纵向继承体系
横向机制:
JDK代理机制:jdk动态代理是由Java内部的反射机制来实现的.jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。
CGlib代理机制:Cglib的原理是对指定的目标类动态生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类和final方法进行代理。
(3)AOP操作相关术语(重点切入点、增强、切面)
spring的AOP操作(基于aspectj的XML方式)
Joinpoint 连接点:类里面可以被增强的方法,这些方法称为连接点
Pointcut 切入点:在类里面可以有很多的方法被增强,但是在实际的操作中值只是增强了add()和update(),则这两个实际增强的方法称为切入点
Advice 通知/增强:实际增强的逻辑,称为增强,例如扩展日志的功能,这个日志功能称为增强
分为:
(1)前置通知:在方法之前执行
(2)后置通知:在方法之后执行
(3)异常通知:方法出现异常
(4)最终通知:在后置之后执行
(5)环绕通知:在方法之前和方法之后都执行,例如获取执行时间
Aspect 切面:把我们的Advice增强应用到具体的Pointcut切入点方法上面,这个过程称为切面
Introduction 引介 :是一种特殊的增强,它为类添加一些属性和方法。这样,即使一个业务类原本没有实现某个接口,通过AOP的引介功能,我们可以动态地为该业务类添加接口的实现逻辑,让业务类成为这个接口的实现类。
proxy 代理:一个类被AOP织入增强后,就产出了一个结果类,它是融合了原类和增强逻辑的代理类。根据不同的代理方式,代理类既可能是和原类具有相同接口的类,也可能就是原类的子类,所以我们可以采用调用原类相同的方式调用代理类。
(4)Spring的AOP操作
1、在spring里面进行AOP操作,使用 AspecJ 实现
AspectJ:面向切面的框架,它扩展了JAVA语言,是一个基于JAVA语言的AOP框架
- (1)aspectj不是spring的一部分,和spring一起使用进行AOP操作
- (2)Spring2.0之后新增加了对 aspectj 支持
2、使用AspectJ 方式实现AOP操作有两种方式
- (1)基于AspectJ 的xml配置
Book类:
package cn.itcast.aop;
public class Book {
public void add(){
System.out.println("add book......");
}
}
MyBook类:增强类对象
package cn.itcast.aop;
import org.aspectj.lang.ProceedingJoinPoint;
//增强类
public class MyBook {
public void befoer1(){
System.out.println("前置before1......");
}
public void after1(){
System.out.println("后置after1......");
}
//环绕通知
public void around1(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
//在方法之前执行
System.out.println("方法之前执行.....");
//执行被增强的方法
proceedingJoinPoint.proceed();
//在方法之后执行
System.out.println("方法之后执行....");
}
}
AspectJ 的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:aop="http://www.springframework.org/schema/aop" 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"> <!-- bean definitions here --> <!--1、 配置对象 --> <bean id="book" class="cn.itcast.aop.Book"></bean> <bean id="myBook" class="cn.itcast.aop.MyBook"></bean> <!-- 2、配置AOP操作 --> <aop:config> <!-- 2.1 配置切入点 --> <aop:pointcut expression="execution(* cn.itcast.aop.Book.add(..))" id="pointcut1"/> <!-- 2.2配置切面 :把增强用到方法上面 --> <aop:aspect ref="myBook"> <!-- 配置增强类型 :method:增强的类里面,使用哪个方法作为前置增强--> <aop:before method="befoer1" pointcut-ref="pointcut1"/> <aop:after-returning method="after1" pointcut-ref="pointcut1"/> <aop:around method="around1" pointcut-ref="pointcut1"/> </aop:aspect> </aop:config> </beans>
测试代码:
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("aopbeans.xml");
Book book=(Book)context.getBean("book");
book.add();
}
结果:
前置before1......
方法之前执行.....
add book......
方法之后执行....
后置after1......
- (2)基于aspectj 的注解方式
- 第一步:在配置文件中设置对象
<bean id="book" class="cn.sdust.aop.Book"></bean> <bean id="myBook" class="cn.sdust.aop.MyBook"></bean>
- 第二步:开启aop操作
<!-- 开启aop操作 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 第三步:在增强类上面使用注解完成AOP操作
Book类
package cn.sdust.aop; public class Book { public void add(){ System.out.println("add book....."); } }
MyBook类
package cn.sdust.aop; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class MyBook { //在方法上面使用注解完成增强配置 @Before(value="execution(* cn.sdust.aop.Book.*(..))") public void before(){ System.out.println("before......"); } @AfterReturning(value="execution(* cn.sdust.aop.Book.*(..))") public void after(){ System.out.println("after......"); } @Around(value="execution(* cn.sdust.aop.Book.*(..))") public void round(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ System.out.println("round--before...."); proceedingJoinPoint.proceed(); System.out.println("round--after...."); } }
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:aop="http://www.springframework.org/schema/aop" 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"> <!-- bean definitions here --> <!-- 开启aop操作 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 创建对象 --> <bean id="book" class="cn.sdust.aop.Book"></bean> <bean id="myBook" class="cn.sdust.aop.MyBook"></bean> </beans>
测试代码
@Test public void testaop(){ ApplicationContext context=new ClassPathXmlApplicationContext("aop.xml"); Book book=(Book) context.getBean("book"); book.add(); }
运行结果
round--before....
before......
add book.....
round--after....
after......
AOP 操作准备:
1、jar包
- 基本jar包
- aspectj 的jar 包
2、xml中的约束有beans、context、aop
<?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:aop="http://www.springframework.org/schema/aop" 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"> <!-- bean definitions here --> </beans>
使用表达式配置切入点
1、切入点:实际增强的方法
2、常用表达式
execution (<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
(1)execution (* com.skd.aop.Book.add(..))//其中的(1)*表示修饰符(2)..表示如果有参数,也包括
(2)execution (* com.skd.aop.Book.*(..)) //Book/类的所有方法
(3)execution (* *.*(..))//所有类的所有方法
(4)execution (* save*(..)) //匹配save开头的所有方法