AOP
1.
1.1 什么是aop?
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
1.2 aop的作用以及优势
作用:运行期间,在代码不修改的情况下,对方法的功能进行增强
优势:减少重复代码,提高开发效率,并且便于维护
1.3 aop的底层实现
实际上,aop的底层是通过spring提供的动态代理技术实现的,在运行期间,spring通过动态代理技术动态的生成代理对象,代理对象方法执行时进行增强功能的介入,去调用目标对象的方法,从而完成功能的增强。
1.4 aop的动态代理技术
常用的动态代理技术:
JDK代理:基于接口的动态代理技术
cglib代理:基于父类的动态代理技术
1.5 JDK的动态代理
//接口
public interface TestInterface{
public void save();
}
//接口的实现
public class Test implements TestInterface{
public void save(){
System.out.println("jdk代理");
}
}
//jdk增强
public class Aoptest{
public void before(){
System.out.println("aop-before");
}
public void after(){
System.out.println("aop-after");
}
}
//
public class boot{
public static void main(String[] args){
//目标对象
final Test test = new Test();
Aoptest aoptest = new aoptest();
Proxy.newProxyInstance(
//目标对象的类加载器
test.getClass().getClassLoader(),
//目标对象相同的接口字节码对象数组
test.getclass().getInterfaces(),
TestInterface proxy = (TestInterface)new InvocationHandler{
//调用代理对象的任何方法,其实质上执行的都是invoke方法
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
//这里使用需要增强的方法before
aoptest.before();
Object object = method.invoke(test,args);
//这里使用需要增强的方法after
aoptest.after();
return object;
}
)
//调用
proxy.save();
}
}
1.6 cglib的动态代理
//不需要实现接口
public class Test{
public void save(){
System.out.println("jdk代理");
}
}
//需要增强的方法
public class Aoptest{
public void before(){
System.out.println("aop-before");
}
public void after(){
System.out.println("aop-after");
}
}
//
public class boot{
public static void main(String[] args){
//目标对象
final Test test = new Test();
//增强对象
Aoptest aoptest = new aoptest();
//1.创建cg增强器
Enhancer enhancer = new Enhancer();
//2.设置父类(目标)
enhancer.setSupperclass(Test.class);
//3.设置回调
enhancer.setCallback(new MethodInterceptor(){
public Object intercept(Object o,Method method,Object[] objects,Methodproxy methodproxy) throw Throwable{
//这里使用需要增强的方法before
aoptest.before();
Object object = method.invoke(test,args);
//这里使用需要增强的方法after
aoptest.after();
return object;
}
});
//3.创建代理对象
Test proxy = (Test)enhancer.create();
proxy.save();
}
}
1.7 aop相关概念
Target(目标对象):代理的目标对象
Proxy(代理):一个类被aop加入增强后,就会产生一个结果代理类
Joinpoint(连接点):所谓的连接点就是那些需要被拦截的点,在spring中,连接点指的就是方法,spring只支持方法类型的连接点。
Pointcut(切点):所谓切入点是指我们需要对哪些Joinpoint进行拦截的定义。
Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。
Aspect(切面):切点和增强(引介)的结合。
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程,spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
1.8 AOP开发事项
1.需要编写的内容
编写目标类的,目标方法
编写切面类,切面类有通知(增强方法)
在配置文件中配置织入关系,即哪些通知和哪些连接点结合
2.AOP技术实现过程
Spring框架监控切入点方法的执行,一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知的方法织入,完成完整代码的逻辑执行。
3.AOP底层使用哪种代理方式
在spring中,框架会根据目标类是否实现了接口来决定采用哪种代理方式。
1.9 基于xml的AOP开发
步骤:
1.导入AOP相关坐标
//porm.xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.3.RELEASE</version>
</dependency>
<!-- aspectj的织入 -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
2.创建目标接口和目标类
//接口
public interface TestAOP{
public void save();
}
//接口的实现
public class Test implements TestAOP{
public void save(){
System.out.println("aop_test。。。。");
}
}
3.创建切面类(内部有增强方法)
//创建切面类
public class aspect{
public void before(){
System.out.println("前置增强。。。。")
}
}
4.将目标类和切面类的对象创建权交给spring
//applicationContext.xml
//目标对象
<bean id="test" class="com.test.Test"></bean>
//切面对象
<bean id="aspect" class="com.test.aspect"></bean>
5.在applicationContext.xml中织入关系
//配置织入,告诉spring框架,哪些方法需要增强
//applicationContext.xml
<!--配置织入:告诉spring框架 哪些方法(切点)需要进行哪些增强(前置、后置...)-->
<aop:config>
<!--声明切面-->
<aop:aspect ref="aspect">
<!--切面:切点+通知-->
<aop:before method="before" pointcut="execution(public void com.test.Test.save())"></aop:before>
</aop:aspect>
</aop:config>
//切点表达式
execution([修饰符]返回值类型 包名.类名.方法名(参数))
访问修饰符可以省略不写
返回值类型、包名、类名、方法名可以使用*号,代表任意
包名和类名之间一个点.代表当前包下的类,..两个点代表当前包以及子包下的类
参数列表可以使用两个点..代表任意个数,任意类型的参数列表
//通知的类型
//通知的配置语法
<aop:通知类型 method="切面类中的方法名" pointcut="切点表达式"></aop:通知类型>
切点表达式的抽取:
当多个切点表达式相同时,可以将切点表达式进行抽取,在增强中使用pointcut-ref属性代替pointcut属性来引用抽取后的切点表达式
<aop:pointcut id="mypointcut" expression="excution(public void com.test.Test.save())"></aop:pointcut>
//之后可以使用mypointcut替代,即:
ponitcut-ref="mypointcut" 等价于:
pointcut="execution(public void com.test.Test.save())"
6.使用
1.10 基于注解的AOP开发
步骤:
1.创建目标接口和目标类(内部有切点)
//接口
public interface TestAOP{
public void save();
}
//接口的实现
public class Test implements TestAOP{
public void save(){
System.out.println("aop_test。。。。");
}
}
2.创建切面类(内部有增强方法)
//创建切面类
public class aspect{
public void before(){
System.out.println("前置增强。。。。")
}
}
3.将目标类和切面类的创建交给spring容器
@Conponent("test ")
public class Test implements TestAOP{
public void save(){
System.out.println("aop_test。。。。");
}
}
@Conponent("myaspect")
public class Aspect{
public void before(){
System.out.println("前置增强。。。。")
}
}
4.在切面类中使用注解织入关系
@Conponent("myaspect")
@Aspect//标注为切面类
public class Aspect{
@Before("切点表达式")
public void before(){
System.out.println("前置增强。。。。")
}
}
5.在配置文件中开启组件扫描和AOP的自动代理
//applicationContext.xml
//目标类的组件扫描
<context:conponent-scan base-package="com.test.Test"/>
//切面类的组件扫描
<context:conponent-scan base-package="com.test.Aspect">
//aop自动代理
<aop:aspectj-autoproxy/>
注解通知的类型:
//通知配置语法:@通知注解("切点表达式")