一、AOP介绍
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
简单的说,AOP就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
AOP是一种思想,面向切面编程思想。在Spring框架内部提供了组件对AOP进行实现,它是在运行期间使用动态代理技术实现的思想。
AOP是OOP(面向对象)的延续,底层实现是动态代理技术。
AOP的两种实现方式:
基于JDK:目标对象必须有接口(proxy是接口的实现)。
基于cglib:目标对象不需要有接口(proxy是目标子类)。
AOP的基本概念、术语
目标对象(target)
代理对象(proxy)
连接点(joinpoint):可以被增强的方法
切(入)点(pointcut): 真正可以被增强的方法
增强/通知(advice):功能增强的方法
切面(aspect):切点+增强
织入(weaver):将切点和增强结合的过程
二、基于xml方式的AOP配置
(一)开发步骤
1、导入aop的jar
spring-aop-4.2.4.RELEASE Spring的aop核心包
spring-aspects-4.2.4.RELEASE Spring的切面包
com.springsource.org.aopalliance-1.0.0 AOP联盟包
com.springsource.org.aspectj.weaver-1.6.8.RELEASE aspectj的织入包
2、定义目标(目标内部有切点)、定义切面(增强在切面内部)
//定义目标对象
public class Target implements TargetInterface {
@Override
public void show() {
//int i = 1/0;
System.out.println("目标执行...");
}
}
//定义切面
public class MyAspect {
public void befor(){System.out.println("前置增强...");}
public void afterReturning(){System.out.println("后置增强...");}
//ProceedingJoinPoint:正在进行的连接点(切点)
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前置增强...");
proceedingJoinPoint.proceed();// 切点方法执行
System.out.println("环绕后置增强...");
}
public void afterThrowing(){System.out.println("异常抛出增强...");}
public void after(){System.out.println("最终增强...");}
}
3、配置目标和切面到Spring容器中
4、配置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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
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
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置目标 -->
<bean id="target" class="com.itheima.aop.Target"></bean>
<!-- 配置切面 -->
<bean id="myAspect" class="com.itheima.aop.MyAspect"></bean>
<!-- 配置AOP的织入 -->
<aop:config>
<!-- 指定切面对象是谁 -->
<aop:aspect ref="myAspect">
<!-- 切面=切点+增强 -->
<aop:pointcut id="mypointcut" expression="execution(public void com.itheima.aop.Target.show(..))"/>
<aop:after method="after" pointcut-ref="mypointcut"/>
</aop:aspect>
</aop:config>
</beans>
(二)配置细节:
<?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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
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
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置目标 -->
<bean id="target" class="com.itheima.aop.Target"></bean>
<!-- 配置切面 -->
<bean id="myAspect" class="com.itheima.aop.MyAspect"></bean>
<!-- 配置aop的织入 -->
<aop:config>
<!-- 指定切面对象是谁 -->
<aop:aspect ref="myAspect">
<!-- 切面=切点+增强 -->
<!-- 细节2:切点表达式的写法
expression写法
示例:execution(public void com.itheima.aop.Target.show())
语法:execution([访问修饰符] 返回值 包.类.方法(参数类型列表))
注意:其中
访问修饰符可以省略
返回值、包、类、方法 可以使用*作为通配符代表任意
参数类型列表 可以使用..作为通配符代表任意
示例:
* com.itheima.service.impl.CustomerServiceImpl.*(..) CustomerServiceImpl的任意方法
* com.itheima.service.impl.*.*(..) 对impl包下的任意类的任意方法
* com.itheima.service.*.*.*(..) 对service包下的任意子包下的任意类的任意方法
* com.itheima.service..*.*.*(..) 对service包下的任意后代包下的任意类的任意方法
-->
<!-- <aop:pointcut expression="execution(public void com.itheima.aop.Target..*(..))" id="myPointcut"/>
<aop:pointcut expression="execution(public void com.itheima.aop.Target.show(..))" id="myPointcut2"/> -->
<!-- 细节1:aop的增强/通知有哪些
aop:before 前置增强
aop:after-returning 后置增强
aop:around 环绕增强
aop:after-throwing 异常抛出增强
aop:after 最终增强
-->
<!-- <aop:before method="before" pointcut-ref="myPointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
<aop:around method="around" pointcut-ref="myPointcut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut"/>
<aop:after method="after" pointcut-ref="myPointcut2"/> -->
<!--通知里面直接写切点表达式-->
<aop:around method="around" pointcut="execution(* com.itheima.aop.*.*(..))"/>
<aop:after method="after" pointcut="execution(* com.itheima.aop.*.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
三、基于注解方式的AOP配置
(一)开发步骤
1、导入AOP的jar(idea建项目时会下载Spring的jar包,所以这里我不手动导入了)
spring-aop-4.2.4.RELEASE spring的AOP核心包
spring-aspects-4.2.4.RELEASE spring的切面包
com.springsource.org.aopalliance-1.0.0 AOP联盟包
com.springsource.org.aspectj.weaver-1.6.8.RELEASE aspectj的织入包
2、定义目标(目标内部有切点)、定义切面(增强在切面内部)
3、配置目标和切面到spring容器中
4、配置aop的织入
配置文件applicationContext_anno.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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
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
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 组件扫描 -->
<context:component-scan base-package="com.itheima.aop_anno"></context:component-scan>
<!-- 开启aop的自动代理 -->
<aop:aspectj-autoproxy/>
</beans>
注解配置代码:
//定义目标
//配置目标到Spring容器中
@Component("target")
public class Target implements TargetInterface {
@Override
public void show() {
System.out.println("目标执行...");
}
}
//定义切面
//配置切面到Spring容器中
@Component("myAspect")
@Aspect
public class MyAspect {
//@Before("execution(* com.itheima.aop_anno.*.*(..))")
public void befor(){System.out.println("前置增强...");}
//@AfterReturning("execution(* com.itheima.aop_anno.*.*(..))")
public void afterReturning(){System.out.println("后置增强...");}
//ProceedingJoinPoint:正在进行的连接点(切点)
//@Around("execution(* com.itheima.aop_anno.*.*(..))")
@Around("MyAspect.pointcut()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前置增强...");
proceedingJoinPoint.proceed();
System.out.println("环绕后置增强...");
}
//@AfterThrowing("execution(* com.itheima.aop_anno.*.*(..))")
public void afterThrowing(){System.out.println("异常抛出增强...");}
//@After("execution(* com.itheima.aop_anno.*.*(..))")
public void after(){System.out.println("最终增强...");}
//<aop:pointcut expression="execution(public void com.itheima.aop.Target.*(..))" id="myPointcut"/>
@Pointcut("execution(* com.itheima.aop_anno.*.*(..))")
public void pointcut(){}
}
//测试
public class AOPtest {
public static void main(String[] args){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext_anno.xml");
TargetInterface target = (TargetInterface) applicationContext.getBean("target");
target.show();
}
}
注意:
注解配置需要在配置文件中配置AOP的自动代理
<!-- 开启aop的自动代理 -->
<aop:aspectj-autoproxy/>
(二)全注解开发
目标对象和切面
//配置目标到Spring容器中
@Component("target")
public class Target implements TargetInterface {
@Override
public void show() {
System.out.println("目标执行...");
}
}
//配置切面到Spring容器中
@Component("myAspect")
@Aspect
public class MyAspect {
//@Before("execution(* com.itheima.aop_allanno.*.*(..))")
public void befor(){System.out.println("前置增强...");}
//@AfterReturning("execution(* com.itheima.aop_allanno.*.*(..))")
public void afterReturning(){System.out.println("后置增强...");}
//ProceedingJoinPoint:正在进行的连接点(切点)
//@Around("execution(* com.itheima.aop_allanno.*.*(..))")
@Around("MyAspect.pointcut()")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕前置增强...");
proceedingJoinPoint.proceed();
System.out.println("环绕后置增强...");
}
//@AfterThrowing("execution(* com.itheima.aop_allanno.*.*(..))")
public void afterThrowing(){System.out.println("异常抛出增强...");}
//@After("execution(* com.itheima.aop_allanno.*.*(..))")
public void after(){System.out.println("最终增强...");}
//<aop:pointcut expression="execution(public void com.itheima.aop.Target.*(..))" id="myPointcut"/>
@Pointcut("execution(* com.itheima.aop_allanno.*.*(..))")
public void pointcut(){}
}
配置类
//配置类
@Configuration
//组件扫描
@ComponentScan("com.itheima.aop_allanno")
//开启AOP的自动代理
@EnableAspectJAutoProxy
public class SpringConfiguration { }
测试
public class AOPtest {
public static void main(String[] args){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
TargetInterface target = (TargetInterface) applicationContext.getBean("target");
target.show();
}
}