一、动态代理
动态代理指的是:在程序的执行过程中,使用jdk的反射机制,创建代理对象,并动态的指定代理的目标类,(就相当于明星的经纪人一样,或者是被告找律师)。
- 动态代理的实现方式常用有两种:
- 使用JDK代理
- 通过CDLIB代理
优点
- java动态代理的优势是实现无侵入式的代码扩展也就是方法的增强;
- 让你可以在不用修改源码的情况下,增强一些方法;
二、AOP
AOP,即面向切面编程,是一种编程范式,它通过将横切关注点(如日志、事务、安全等)与业务逻辑分离,从而实现代码的模块化和可维护性。在Java中,AOP由Spring框架提供支持,下面我们来详细了解一下。
Spring中的AOP是基于动态代理实现的,即 JDK动态代理和Cglib动态代理。
将代码切割开来,插入方法,所以说的是面向切面编程
1. AOP的核心概念
- 切面(Aspect):封装横切关注点的模块。在AOP中,一个切面通常包含了多个通知(Advice)以及相关的切点(Pointcut),用于描述在何处应该应用这些通知。
- 通知(Advice):切面中的一个方法,它定义了在什么时候、在哪里以及如何修改目标对象的行为,包括前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)和环绕通知(Around)等几种类型。
- 切点(Pointcut):指定在哪些Join Point上应用通知。Join Point是程序执行过程中可以插入切面的点,例如方法调用、属性访问、异常处理等。
- 连接器(Weaving):将切面与目标对象合并的过程。连接器可以在编译期、类加载期或运行期进行,并可以使用不同的方式实现,如编译时增强、类加载时增强、动态代理等。
2. AOP的应用场景
- 日志记录:记录程序中各个方法的执行时间、参数、返回值等信息。
- 安全检查:在调用某些敏感方法前,先进行用户身份验证或权限校验。
- 性能监控:统计程序中各个方法的运行时间、调用次数等信息,用于优化性能。
- 事务管理:实现一些跨越多个方法的事务操作。
3. AOP的实现方式
- 基于代理的AOP:使用JDK动态代理或CGLIB生成代理对象,在代理对象中添加通知逻辑。
- 基于AspectJ的AOP:利用AspectJ提供的注解、表达式和语法,直接在代码中定义切面。
代码示例:
下代码之前先导入相应的jar包
书写接口和实体类:
public interface Person {
void eat();
}
实体类:
public class Zhangyu implements Person {
@Override
public void eat() {
System.out.println("eat...");
}
}
增强类:
public class JJR {
public void before(){
System.out.println("***");
}
public void be2(){
System.out.println("*****");
}
public void be3(){
System.out.println("*******");
}
public void be4(){
System.out.println("*********");
}
}
在src下书写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/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--1.把所有类的对象交给IOC容器进行管理-->
<bean id="Zhangyu" class="com.dhh.service.impl.Zhangyu"></bean>
<bean id="jjr" class="com.dhh.servlet.JJR"></bean>
<!--2.AOP的配置:让增强类 的 哪个方法 动态进行何种增强 核心类 的 哪个方法-->
<aop:config>
<!--指定增强类并且起个名字-->
<aop:aspect id="qwe" ref="jjr">
<!--前置通知/增强:在核心类方法执行之前 进行 增强-->
<aop:before method="before" pointcut="execution(* *..Zhangyu.*(..))"/>
<aop:after-returning method="be2" pointcut="execution(* *..Zhangyu.*(..))"/>
<aop:after-throwing method="be3" pointcut="execution(* *..Zhangyu.*(..))"/>
<aop:after method="be4" pointcut="execution(* *..Zhangyu.*(..))"/>
</aop:aspect>
</aop:config>
</beans>
在Test类中进行测试:
package com.dhh.Test;
import com.dhh.service.Person;
import com.dhh.service.impl.Zhangyu;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test01 {
public static void main(String[] args) {
// 加载配置
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
// 获取代理对象
Person p = context.getBean(Person.class);
p.eat();
}
}
优点:提高代码的可维护性和扩展性,将横切关注点与业务逻辑分离,避免代码重复和紧耦合。
缺点:增加代码的复杂度,可能影响程序的执行效率。
运行结果: