-
什么是AOP?
AOP(Aspect Oriented Programming)意为:面向切面编程,体现了横切的思想,意思是在添加某项功能的时候,是以切面插入的方式实现的,对原有的代码不会产生改变。通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
-
AOP在spring中的作用:在不改变原有代码的情况下,去增加新的功能。
- 横切关注点:跨越应用程序多个模块的方法或功能。即与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等 …
- 切面(ASPECT):横切关注点被模块化的特殊对象。即,它是一个类。
- 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知 执行的 “地点”的定义。
- 连接点(JointPoint):与切入点匹配的执行点。
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
-
aop的实现
- 需要导入相应的包
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>xxx</version> </dependency>
- 第一种实现方式:通过spring API 编写业务接口实现类
//业务接口 public interface UserService {void add(); } //业务实现类 public class UserServiceImpl implements UserService {@Overridepublic void add() {System.out.println("执行了add方法");} }
- 编写增强类:前置和后置
public class Log implements MethodBeforeAdvice {/*** target:目标对象* args:参数* method:目标对象的方法*/@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println(target.getClass().getName()+"执行了"+method.getName()+"方法");} } public class AfterLog implements AfterReturningAdvice {/*** returnValue:返回值*/@Overridepublic void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {System.out.println("执行了"+method.getName()+"方法,返回结果"+returnValue);} }
- 编写配置文件,要导入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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><!--注册bean--><bean id="userService" class="com.test.service.UserServiceImpl"/><bean id="log" class="com.test.log.Log"/><bean id="afterLog" class="com.test.log.AfterLog"/><!--方式一:使用原生Spring API接口 --><!--配置aop:需要导入aop的约束--><aop:config><!--切入点:expression:表达式,execution(要执行的位置! * * * * *) --><aop:pointcut id="pointcut" expression="execution(* com.test.service.UserServiceImpl.*(..))"/><!--执行环绕增加!--><aop:advisor advice-ref="log" pointcut-ref="pointcut"/><aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/></aop:config> </beans>
- 测试
@Test public void test1(){ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = context.getBean("userService", UserService.class);userService.add(); }
- 第二种方式:自定义类实现AOP
public class SelfPointcut {public void before() {System.out.println("使用前");}public void after() {System.out.println("使用后");} }
- 编写配置类
<beans> <!--方式二:自定义类--><bean id="selfPointcut" class="com.test.self.SelfPointcut"/><aop:config><!--自定义切面, ref 要引用的类--><aop:aspect ref="selfPointcut"><!--切入点--><aop:pointcut id="point" expression="execution(* com.test.service.UserServiceImpl.*(..))"/><!--通知--><aop:before method="before" pointcut-ref="point"/><aop:after method="after" pointcut-ref="point"/></aop:aspect></aop:config> </beans>
- 使用注解的方式:编写使用注解的实现类
@Aspect// 标注此类是一个切面 public class AnnotationPointCut {@Before("execution(* com.test.service.UserServiceImpl.*(..))")public void before(){System.out.println("方法执行前");}@After("execution(* com.test.service.UserServiceImpl.*(..))")public void after(){System.out.println("方法执行后");} }
- 编写配置
<!--方式三--> <bean id="annotationPointCut" class="com.test.self.AnnotationPointCut"/> <!--开启注解支持! JDK(默认 proxy-target-class="false") cglib(proxy-target-class="true")--> <aop:aspectj-autoproxy/>
-
spring aop JDK动态代理和cglib动态代理的区别
-
Spring AOP 支持两种类型的动态代理:JDK 动态代理和 CGLIB 动态代理。它们之间有以下区别:
-
基于类型:JDK 动态代理是基于接口的代理,而 CGLIB 动态代理是基于类的代理。
-
代理对象创建:JDK 动态代理通过 Java 自带的 java.lang.reflect.Proxy 创建代理对象,该对象必须实现一个或多个接口。CGLIB 动态代理通过字节码生成技术创建代理对象,无需目标类实现接口,直接继承目标类。
-
性能:JDK 动态代理在运行时需要使用反射,导致较低的性能。CGLIB 动态代理通过生成字节码,避免了反射,因此通常比 JDK 动态代理速度更快。
-
对象类型:JDK 动态代理只能代理具有接口的目标对象,不适用于没有接口的类。CGLIB 动态代理可以代理任何类,包括没有实现接口的类。
-
继承:JDK 动态代理只能代理目标对象的接口方法,不能代理其父类中的方法。CGLIB 动态代理可以代理目标类及其父类中的方法。
-
综上所述,选择使用 JDK 动态代理还是 CGLIB 动态代理取决于具体的需求和场景。如果目标对象实现了接口并且对性能要求较高,可以选择 JDK 动态代理;如果目标对象没有实现接口或者对性能要求不那么苛刻,可以选择 CGLIB 动态代理。默认情况下,Spring AOP 使用 JDK 动态代理,但在某些情况下会自动切换到 CGLIB 动态代理。
-