在Spring AOP 1.0中,将增强类要增强的业务逻辑代码织入到被代理对象(目标对象)中,被织入增强代码的目标对象是不能够直接修改原有的目标对象,而是会生成一个被代理对象(通过字节码操作工具产生新的字节码,通过加载形成代理对象),在了解SpringAop1.0是如何实现增强类织入目标对象前,首先得了解增强类可以实现的几个接口:
一、 Advice类型(增强类型)
Spring AOP支持5种类型的通知(增强)
二、 SpringAOP 1.0中动态代理的基本用法
在SpringAOP 1.0中,实现动态代理,要将增强类中的增强代码织入到目标对象中,需要通过以下几个步骤,分别是:导入jar包;定义实现于接口的增强类;在xml文件中进行相关的配置;下面通过代码来对整个过程进行学习:
(一)定义实现于接口的的实现类
在这个地方,需要定义接口和接口的实现类,在SpringAOP 1.0中,对接口实现类的动态代理,采用的技术是JDK技术,即Proxy及相关子类这些字节码操作工具类,在SpringAOP 1.0中,xml配置文件中加载的字节码操作工作类是:ProxyFactoryBean。这里先定义接口和接口的实现类,代码如下:
1.定义接口:
// TODO: 2021/6/25 定义一个被代理对象的接口,被代理对象(目标对象)将实现于这个接口
public interface Aop2UserInterface {
void showInfo();
}
2.定义实现于上面接口的实现类
// TODO: 2021/6/25 这是一个实现于接口的实现类,也是被代理对象类(目标对象类)
public class Aop2UserImpl implements Aop2UserInterface {
@Override
public void showInfo() {
System.out.println("这个是被代理类(目标对象),实现于一个接口");
}
}
(二)定义一个增强类
增强类对象也是实现于接口,根据实现的接口不同,决定了决定了增强代码(位置方法中)是在被代理对象方法中的哪个位置,其主要接口有如下几类:
1:MethodBeforeAdvice:在方法执行前添加功能
2:AfterReturningAdvice:在方法执行后添加功能
3:MethodInterceptor:在方法执行前后添加功能
4:ThrowsAdvice:在方法抛出异常后添加功能
5:IntroductionInterceptor:在目标类中添加新方法和属性
// TODO: 2021/6/25 这里是增强的业务逻辑代码,主要向指定目标对象(被代理对象)中织 入,织入后,会动态产生一个代理对象
public class Aop2UserAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(method.getName() +":[" + new Date().getTime() + "];description:" + "这是增强类,实现于MethonBeforeAdvice接口,增强类包含" +
"用于增强业务逻辑的方法");
}
}
(三)在配置文件xml中进行配置(重点掌握)
在SpringAOP 1.0中,也是在xml中进行相关配置,配置主要分为以下几个步骤:
1.添加jar依赖包
<!-- TODO:添加CGLIB包,里面主要包含的字节码操作工作类(数据空间) -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
2.在配置文件中加载目标对象(被代理对象)
<!-- TODO:在配置文件中定义:目标对象(被代理类) -->
<bean id="aop2User" class="aop2.Impl.Aop2UserImpl"/>
3.在配置文件中加载advice(增强,也可以称之为通知)
在配置文件中需要配置advice,advice可也被看作是增强,也可以是通知,他是实现于不同接口的袜现类,存在交叉业务逻辑代码 ,这些代码会被织入到指定的切入点。
<!-- TODO:在配置文件中加载增强类,增强类实现于不同的接口,这些接口决定了增强代码(位置方法中)是在被代理对象方法中的哪个位置 -->
<!-- TODO:其主要接口有如下几类:
1:MethodBeforeAdvice:在方法执行前添加功能
2:AfterReturningAdvice:在方法执行后添加功能
3:MethodInterceptor:在方法执行前后添加功能
4:ThrowsAdvice:在方法抛出异常后添加功能
5:IntroductionInterceptor:在目标类中添加新方法和属性-->
<bean id="methonadvice" class="aop2.advice.Aop2UserAdvice"/>
3.配置Pointcut
可以理解为:指定的advice(增强类)用于哪些指定的方法名中。通过设置两个属性来确定,一个是增强类属性,这个属性指定使用哪个增强类;另一个是指定方法名,明确哪些方法可以使用这些增强类,可以简单的理解为这是一个增强类配置,明确增强类代码用于哪些方法名,也就是增强类代码可以织入到哪些指定的方法中,以名字来匹配方法。具体代码如下:
<!-- TODO:这是一个配置器,其主要用途是:指定哪一个增强类的业务逻辑代码用于所指定的切入点,切入点是用指定名字来匹配方法名的 -->
<bean id="showinfoadvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!-- TODO: 下面这行主要指明是用哪个增强类-->
<property name="advice" ref="methonadvice"/>
<!-- TODO:下面主要指定切入点,采取名字匹配方法名的方式,即列表指定的名称也是被代理对象方法的名称 -->
<property name="mappedNames">
<list>
<!-- TODO:下面就是被代理对象(目标对象)方法的名称 -->
<value>showInfo</value>
</list>
</property>
</bean>
4. 配置代理(ProxyFactoryBean)
ProxyFactoryBean是CGLIB中的一个字节码操作工作类,通过传入相关的属性,可以动态的生成一个字节码,从而产生对应的方法空间和数据空间(也就是代理类),竟然是字节码操作工作,他需要传入以下三个属性:
- 接收一个被代理对象(目标对象)属性,生产的代理对象也就是用于代理此目标对象的
- 接收一个接口的结构信息,字节码操作工具也是依据此结构信息来重新生成字节码
- 接收一个增强类配置对象,该对象明确了增强类用于哪些指定的切点,字节码操作工具会依据此配置对象在生成的代理类字节码中哪些方法使用交叉业务逻辑
<!-- TODO:配置一个字节码操作工具类对象,该对象主要是采用JDK技术,会动态生个字节码,通过加载产生相应的方法空间和数据空间(也称代理对象),接收三个属性
一是:接收一个被代理对象(目标对象)属性,生产的代理对象也就是用于代理此目标对象的
二是:接收一个接口的结构信息,字节码操作工具也是依据此结构信息来重新生成字节码
三是:接收一个增强类配置对象,该对象明确了增强类用于哪些指定的切点,字节码操作工具会依据此配置对象在生成的代理类字节码中哪些方法使用交叉业务逻辑-->
<bean id="useraop2" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="aop2User"/>
<property name="interfaces">
<list>
<value>aop2.Aop2UserInterface</value>
</list>
</property>
<property name="interceptorNames">
<list>
<value>showinfoadvisor</value>
</list>
</property>
</bean>
4. 对配置文件进行加载,测试生成的动态代理对象
@Test
// TODO: 2021/6/25 此方法主要用主测试在Spring AOP 1.0中,增强类定义的交叉业务逻辑是如何织入目标对象(被代理对象) 且动态生成代理对象的
public void test75() {
ApplicationContext ac = new ClassPathXmlApplicationContext("aop2/aop2.xml");
Aop2UserInterface proxyAop2 = (Aop2UserInterface) ac.getBean("useraop2");
proxyAop2.showInfo();
}