一、什么是AOP
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现 程序功能的统一维护的一种技术。
利用AOP可以对业务逻辑的各个部分进行隔离,从而使 得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
![](https://img-blog.csdnimg.cn/ccff039269864715a25de1d3588a19a1.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiK5YW15LyQ55y4,size_20,color_FFFFFF,t_70,g_se,x_16)
二、Aop在Spring中的作用
提供声明式事务;允许用户自定义切面
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要
- 关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....
- 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
- 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知 执行的 “地点”的定义。
- 连接点(JointPoint):与切入点匹配的执行点。
SpringAOP
中,通过
Advice
定义横切逻辑,
Spring
中支持
5
种类型的
Advice:
![](https://img-blog.csdnimg.cn/d5e1b486ddb54d7bb5a312599485d89e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5LiK5YW15LyQ55y4,size_20,color_FFFFFF,t_70,g_se,x_16)
即 Aop 在 不改变原有代码的情况下 , 去增加新的功能 .
三、使用Spring实现Aop
使用AOP织入,需要导入一个依赖包!
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8</version>
<scope>runtime</scope>
</dependency>
通过springAPI实现、通过自定义切面实现、通过注解实现
方式一:通过 Spring API 实现
1、业务接口
public interface UserService {
public void add();
public void delete();
public void update();
public void quray();
}
2、业务实现类
public class UserServiceImp implements UserService{
@Override
public void add() {
System.out.println("增加了用户");
}
@Override
public void delete() {
System.out.println("删除了用户");
}
@Override
public void update() {
System.out.println("更新了用户");
}
@Override
public void quray() {
System.out.println("查询了用户");
}
}
3、编写增强类,一个前置增强、一个后置增强
public class BeforeLog implements MethodBeforeAdvice {
//method : 要执行的目标对象的方法
// objects : 被调用的方法的参数
// Object : 目标对象
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行了");
}
}
public class AfterLog implements AfterReturningAdvice {
//returnValue 返回值 //method被调用的方法 //args 被调用的方法的对象的参数 //target 被调用的目标对象
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"方法执行了"+",返回值是:"+returnValue);
}
}
4、最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束 .
<!-- 注册bean-->
<bean id="userServiceImp" class="com.jia.service.UserServiceImp"/>
<bean id="afterLog" class="com.jia.service.AfterLog"/>
<bean id="beforeLog" class="com.jia.service.BeforeLog"/>
<!-- aop配置-->
<aop:config>
<!--切入点 expression:表达式匹配要执行的方法,第一个代表返回的类型,*表示任意类型-->
<aop:pointcut id="pointcut" expression="execution(* com.jia.service.UserServiceImp.*(..))"/>
<!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
</aop:config>
//测试
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//代理的是接口,不是实现类
UserService userService = (UserService) context.getBean("userServiceImp");
userService.add();
}
}
方式二:自定义切面来实现Aop
目标业务类不变依旧是userServiceImpl
1、写我们自己的一个切入类
//自定义切面
public class DiyPointcut {
public void before(){
System.out.println("---------方法执行前---------");
}
public void after(){
System.out.println("---------方法执行后---------");
}
}
2、注册bean和aop
<bean id="userServiceImp" class="com.jia.service.UserServiceImp"/>
<bean id="diy" class="com.jia.service.DiyPointcut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="pointcut" expression="execution(* com.jia.service.UserServiceImp.*(..))"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
3、测试
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("userServiceImp");
userService.add();
}
}
方式三:使用注解实现
1、编写一个注解实现的增强类
@Aspect
public class AnnotationPointcut {
@Before("execution(* com.jia.service.UserServiceImp.*(..))")
public void before(){
System.out.println("--------方法执行前--------");
}
@After("execution(* com.jia.service.UserServiceImp.*(..))")
public void after(){
System.out.println("---------方法执行后---------");
}
@Around("execution(* com.jia.service.UserServiceImp.*(..))")
public void around(ProceedingJoinPoint pj) throws Throwable {
System.out.println("环绕前");
System.out.println(pj.getSignature());//签名
Object proceed = pj.proceed();
System.out.println("环绕后");
System.out.println(proceed);
}
}
2、在
Spring
配置文件中,注册
bean
,并增加支持注解的配置
<bean id="userServiceImp" class="com.jia.service.UserServiceImp"/>
<bean id="annotaionPoint" class="com.jia.service.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>
- 通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspectJ切面 的bean创建代理,织入切面。当然,spring 在内部依旧采用 AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被 <aop:aspectj-autoproxy />隐藏起来了
- <aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态 代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用 CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接 口,则spring将自动使用CGLib动态代理。