Spring_AOP_相关概念和基于xml、Java的配置

AOP出现的背景

  • 分离关注
    分离关注就是将某一通用的需求功能从不相关的类中分离出来,使得很多类共享一个行为,当行为需求需要变化时,只需让该行为发生变化,不必修改其他类
    设计模式追求的本质就是调用者与被调用者之间的解耦
  • OOP
    说到AOP,不得不提OOP,面向对象编程(三大特征:封装、继承、多态)是针对问题领域中以及处理过程中存在的实体及其属性和行为进行抽象和封装,从继承和多态的特性可以看出OOP的核心结构是纵向的,目的是获得清晰高效的逻辑单元划分
  • AOP
    AOP的全程是Aspect Oriented Programming,提供了另一个角度来完善OOP。核心思想就是将应用程序中业务逻辑部分与提供支持的通用服务部分进行分离

相关概念

  • 横切关注点(Cross-cutting concerns)
    横切关注点指的是在一个服务流程中与业务逻辑无关的系统服务逻辑。一个横切关注点可以横切多个对象。
  • 切面(Aspect)
    将散落在业务对象中的横切关注点独立出来在Spring中使用常规类来实现
    切面的实现有两种方式:
    1. 围绕通知(around advice)实现MethodInterceptor
    2. Advisor:Advice+Pointcut
  • 连接点(Joinpoint)
    程序执行过程中明确的点,在Spring中连接点就是一个方法调用
  • 通知(Advice)
    AOP框架在特定的连接点执行的动作。许多AOP框架包括Spring都是以拦截器为通知模型,维护一个围绕连接点的拦截器链
  • 切入点(Pointcut)
    连接点的匹配条件。通知和切入点表达式匹配的连接点进行关联
  • 引入(Introduction)
    添加防火或者字段到被通知的类。
  • 目标对象(Target Object)
    被通知或者切面的对象,或者称作被代理的对象
  • AOP代理(AOP Proxy)
    AOP框架创建的包含通知的对象。
  • 织入(Weave)
    通知被应用到对象之上的过程。

Spring动态代理技术

因为 Java 反射机制可以生成任意类型的动态代理类。 JDK 动态代理主要涉及到
java.lang.reflect 包中的两个类:Proxy 和 InvocationHandler 接口 。InvocationHandler 是代理实例的调用处理程序 实现的接口,每个代理实例都具有一个关联的调用处理程序,对代理实例调用方法时, 通过反射机制调用目标类的代码。Proxy 利用InvocationHandler 动态创建一个符合某一接口的实例,生成目标类的代理对象。 JDK 的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用 JDK 代理,这就要使用 cglib 动态代理了

CGLIB 是针对类实现代理, 原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对 final 修饰的类进行代理;
CGLib 封装了 asm(字节码编码框架),可以再运行期动态生成新的 class。

对比:
JDK 创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过 CGLib 创建动态代理。
默认的策略是如果目标类是接口,则使用 JDK 动态代理技术,否则使用 Cglib 来生成代理。可 以 强 制 使 用 CGlib ( 在 spring 配 置 中 加 入 <aop:aspectj-autoproxy
proxy-target-class=“true”/>)

基于xml的AOP配置

  • 首先用到spring框架就需要在pom.xml文件中加入依赖
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.12.RELEASE</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<bean id="arithImpl" class="com.test.demo.ArithImpl"></bean>
	<bean id="userDao" class="com.test.demo.UserDao"></bean>
	<!-- 通知对象 -->
	<bean id="myMethodBeforeAdvice" class="com.test.advice.MyMethodBeforeAdvice"></bean>
	<bean id="myAfterReturningAdvice" class="com.test.advice.MyAfterReturningAdvice"></bean>
	<bean id="myAroundAdvice" class="com.test.advice.MyAroundAdvice"></bean>
	<bean id="myExceptionAdvice" class="com.test.advice.MyExceptionAdvice"></bean>
	<!-- 切面-->
	<bean id="myMethodBeforeAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
		<property name="advice" ref="myMethodBeforeAdvice"></property>
		<!-- 使用正则表达式来匹配类和方法名称
			匹配 的完整类名和方法名 例如:com.test.demo.Arith.plus
			. 匹配任意字符
			? 匹配0个或者1个
			+ 匹配1个或者多个
			* 匹配0个或者多个
		 -->
		<property name="patterns">
			<array>
				<!-- 匹配某个类中的plus方法 -->
				<value>.+\.plus</value>
			</array>
		</property>
	</bean>
	<!-- 自动的将指定目标对象的代理对象创建出来 
		ioc容器中 目标对象bean的名字 对应的实际是代理对象
	-->
	<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<property name="beanNames">
			<array>
				<value>arithImpl</value>
				<value>*Dao</value>
			</array>
		</property>
		<property name="interceptorNames">
			<array>
				<value>myExceptionAdvice</value>
				<value>myAfterReturningAdvice</value>
				<value>myMethodBeforeAdvisor</value>
				<value>myAroundAdvice</value>
			</array>
		</property>
	</bean>
</beans>

基于Java配置

package com.test;

import org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator;
import org.springframework.aop.support.RegexpMethodPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import com.test.advice.MyMethodBeforeAdvice;

@Configuration
@ComponentScan({"com.test.advice","com.test.demo"})
public class AppConfig {
	
	@Autowired
	private MyMethodBeforeAdvice myMethodBeforeAdvice;
	
	@Bean
	public RegexpMethodPointcutAdvisor myMethodBeforeAdvisor() {
		RegexpMethodPointcutAdvisor advisor = new RegexpMethodPointcutAdvisor();
		advisor.setAdvice(myMethodBeforeAdvice);
		advisor.setPatterns(new String[] {".+\\.plus"});
		return advisor;
	}
	
	@Bean
	public BeanNameAutoProxyCreator beanNameAuto() {
		BeanNameAutoProxyCreator creator = new BeanNameAutoProxyCreator();
		creator.setBeanNames(new String[] {"arithImpl","*Dao"});
		creator.setInterceptorNames(new String[] {"myExceptionAdvice","myAfterReturningAdvice",
				"myMethodBeforeAdvisor","myAroundAdvice"});
		return creator;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值