SSM-Spring Aop

SSM学习第三天–Spring Aop



Spring Aop

一、Aop

Aop(Aspect Oriented Programming):面向切面编程
利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

二、Aop术语

来自https://blog.csdn.net/qq_41981107/article/details/87920537

连接点(Joinpoint) 程序执行的某个特定位置,如某个方法调用前,调用后,方法抛出异常后,这些代码中的特定点称为连接点。简单来说,就是在哪加入你的逻辑增强
连接点表示具体要拦截的方法,上面切点是定义一个范围,而连接点是具体到某个方法
切点(PointCut) 每个程序的连接点有多个,如何定位到某个感兴趣的连接点,就需要通过切点来定位。比如,连接点–数据库的记录,切点–查询条件
切点用于来限定Spring-AOP启动的范围,通常我们采用表达式的方式来设置,所以关键词是范围
增强(Advice) 增强是织入到目标类连接点上的一段程序代码。在Spring中,像BeforeAdvice等还带有方位信息
通知是直译过来的结果,我个人感觉叫做“业务增强”更合适 对照代码就是拦截器定义的相关方法,通知分为如下几种:
前置通知(before) 在执行业务代码前做些操作,比如获取连接对象
后置通知(after) 在执行业务代码后做些操作,无论是否发生异常,它都会执行,比如关闭连接对象
异常通知(afterThrowing) 在执行业务代码后出现异常,需要做的操作,比如回滚事务
返回通知(afterReturning) 在执行业务代码后无异常,会执行的操作
环绕通知(around) 这个目前跟我们谈论的事务没有对应的操作,所以暂时不谈
目标对象(Target) 需要被加强的业务对象
织入(Weaving) 织入就是将增强添加到对目标类具体连接点上的过程。
织入是一个形象的说法,具体来说,就是生成代理对象并将切面内容融入到业务流程的过程。
代理类(Proxy) 一个类被AOP织入增强后,就产生了一个代理类。
切面(Aspect) 切面由切点和增强组成,它既包括了横切逻辑的定义,也包括了连接点的定义,SpringAOP就是将切面所定义的横切逻辑织入到切面所制定的连接点中。
比如上文讨论的数据库事务,这个数据库事务代码贯穿了我们的整个代码,我们就可以这个叫做切面。 SpringAOP将切面定义的内容织入到我们的代码中,从而实现前后的控制逻辑。 比如我们常写的拦截器Interceptor,这就是一个切面类
图片来自https://blog.csdn.net/qq_41981107/article/details/87920537


三、AspectJ开发

AspectJ是一种基于Java语言的AOP框架,提供强大的AOP功能。使用AspectJ实现AOP有两种方式:

1)基于XML的声明式AspectJ

通过XML文件来定义切面、切入点、通知。所有定义都是在<aop:config>元素内,其子元素包括<aop:pointcut>、<aop:advisor><aop:aspect>

常用配置代码(示例):

<!-- 1 切面 -->
	<bean id="myAspect" class="com.ssm.aspectj.xml.MyAspect" />
	<!-- 2aop编程 -->
	<aop:config>
		<!-- 1.配置切面 -->
		<aop:aspect id="aspect" ref="myAspect">
			<!-- 2.配置切入点 -->
			<aop:pointcut expression="execution(* com.ssm.aspectj.*.*(..))"	id="myPointCut" />
			<!-- 3.配置通知 -->
				<!-- 前置通知 -->
				<aop:before method="myBefore" pointcut-ref="myPointCut" />
				<!--后置通知--> 
				<aop:after-returning method="myReturning" pointcut-ref="myPointCut" returning="returnVal"/> 
				<!--环绕通知 -->
				<aop:around method="myAround" pointcut-ref="myPointCut" />
				<!--异常通知 -->
				<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="throwable" />
				<!--最终通知 -->
				<aop:after method="myAfter" pointcut-ref="myPointCut" />
		</aop:aspect>
	</aop:config>

具体步骤:
1、配置切面
<aop:aspect>元素包含两个属性:id(用来定义该切面的唯一标识名称)、ref(用于引用普通的Spring Bean如上述代码中的myAspect)
2、配置切入点
通过<aop:pointcut>元素来定义,当<aop:pointcut>元素作为<aop:config>元素的子元素时,表示该切入点是全局切入点,可多个切面公用。当<aop:pointcut>作为<aop:aspect>的子元素,则为当前切面有效。
包含两个属性:id(用来定义该切入点的唯一标识名称)、expression(用于指定切入点关联的切入点表达式)
<aop:pointcut expression="execution(* com.ssm.aspectj.*.*(..))"/>表示匹配com.ssm.aspectj包中任意类的任意方法的执行。
expression表达式主体;
第1个*表示返回类型、使用*代表所有类型;com.ssm.aspectj表需要拦截的包名;
后第2个*表类名,使用*表所有的类;
第3个*表方法名,使用*表所有方法;
后面()表方法的参数,中的..表任意参数
注意第一个*与包名之间有空格
格式
3、配置通知
通知的常用属性及其描述
在这里插入图片描述
演示代码
(1)创建一个名为chapter03的动态Web项目;
在导入jar包时要在基础包中加入
在这里插入图片描述
(2)在chapter03项目的src目录下,创建一个com.ssm.aspectj包,在包里创建UserDao类,创建两个方法;

package com.ssm.aspectj;
public interface UserDao {
	public void insert();
	public void delete();
}

(3)在 com.ssm.aspectj包中,创建 UserDao接口的实现类 UserDaolmpl;

package com.ssm.aspectj;

import org.springframework.stereotype.Repository;

@Repository("userDao")
public class UserDaoImpl implements UserDao{

	public void insert() {
		//int i=10/0;
		System.out.println("添加用户");
		
	}

	public void delete() {
		System.out.println("删除用户");
		
	}

}

(4)在chapter03项目的src目录下,创建一个 com. ssm.aspectj.xml包,包中创建切面类MyAspect;

package com.ssm.aspectj.xml;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

/*
 * 切面类,此类编写通知
 * */
public class MyAspect {
	
	//前置通知
	public void myBefore(JoinPoint joinPoint){
		System.out.print("前置通知:模拟执行权限检查");
		System.out.print("目标类为:"+joinPoint.getTarget());
		System.out.println(",被植入增强处理的目标方法为:"+joinPoint.getSignature().getName());
	}
	//后置通知
	public void myReturning(JoinPoint joinPoint){
		System.out.print("后置通知:模拟记录日志");
		System.out.println("被植入增强处理的目标方法为:"+joinPoint.getSignature().getName());
	}
	//环绕通知
	public Object myAround(ProceedingJoinPoint point)throws Throwable{
		System.out.println("环绕开始:执行目标方法,模拟开启事务");
		Object obj=point.proceed();
		System.out.println("环绕结束,执行目标方法之后,模拟关闭事务");
		return obj;	
	}
	//异常通知
	public void myAfterThrowing(JoinPoint joinPoint,Throwable throwable){
		System.out.println("异常通知,错误了"+throwable.getMessage());
	}
	//最终通知
	public void myAfter(){
		System.out.println("最终通知,模拟方法结束后释放资源");
	}
		
}

(5)在 com. ssm.aspectj.xml包中,创建配置文件applicationContext. 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:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	<!-- 1 目标类 -->
	<bean id="userDao" class="com.ssm.aspectj.UserDaoImpl" />
	<!-- 2 切面 -->
	<bean id="myAspect" class="com.ssm.aspectj.xml.MyAspect" />
	<!-- 3 aop编程 -->
	<aop:config>
		<!-- 1.配置切面 -->
		<aop:aspect id="aspect" ref="myAspect">
			<!-- 2.配置切入点 -->
			<aop:pointcut expression="execution(* com.ssm.aspectj.*.*(..))"	id="myPointCut" />
			<!-- 3.配置通知 -->
				<!-- 前置通知 -->
				<aop:before method="myBefore" pointcut-ref="myPointCut" />
				<!--后置通知--> 
				<aop:after-returning method="myReturning" pointcut-ref="myPointCut" returning="returnVal"/> 
				<!--环绕通知 -->
				<aop:around method="myAround" pointcut-ref="myPointCut" />
				<!--异常通知 -->
				<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="throwable" />
				<!--最终通知 -->
				<aop:after method="myAfter" pointcut-ref="myPointCut" />
		</aop:aspect>
	</aop:config>
</beans>

(6)在com. ssm.aspectj. xm包下,创建测试类TestXmlAspect。

package com.ssm.aspectj.xml;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ssm.aspectj.UserDao;

public class TextXmlAspect {

	public static void main(String[] args) {
		String xmlPath="com/ssm/aspectj/xml/applicationContext.xml";
		ApplicationContext app=new ClassPathXmlApplicationContext(xmlPath);
		UserDao userDao=(UserDao)app.getBean("userDao");
		userDao.insert();
		userDao.delete();
	}
}

运行结果如下:

三月 20, 2022 2:10:06 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@817b38: startup date [Sun Mar 20 14:10:06 CST 2022]; root of context hierarchy
三月 20, 2022 2:10:07 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [com/ssm/aspectj/xml/applicationContext.xml]
前置通知:模拟执行权限检查目标类为:com.ssm.aspectj.UserDaoImpl@1c072cb,被植入增强处理的目标方法为:insert
环绕开始:执行目标方法,模拟开启事务
添加用户
最终通知,模拟方法结束后释放资源
环绕结束,执行目标方法之后,模拟关闭事务
后置通知:模拟记录日志被植入增强处理的目标方法为:insert
前置通知:模拟执行权限检查目标类为:com.ssm.aspectj.UserDaoImpl@1c072cb,被植入增强处理的目标方法为:delete
环绕开始:执行目标方法,模拟开启事务
删除用户
最终通知,模拟方法结束后释放资源
环绕结束,执行目标方法之后,模拟关闭事务
后置通知:模拟记录日志被植入增强处理的目标方法为:delete

包结构:
在这里插入图片描述


2)基于注解的声明式AspectJ

注释名描述
@Aspect定义一个切面
@PointCut定义切入点表达式
@Before定义前置通知
@AfterReturning定义后置通知
@Around定义环绕通知
@AfterThrowing定义异常通知
@After定义最终通知

演示代码

创建 com.ssm.aspectj.annotation包新建MyAspect类进行修改

package com.ssm.aspectj.annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
//定义切面类
@Aspect
//由于该类在Spring中作为组件使用,要添加@Component注解才能够生效
@Component
public class MyAspect {
		//定义切入点
		@Pointcut("execution(* com.ssm.aspectj.*.*(..))")
		//切入点方法
		public void myPointCut(){}
		//前置通知
		@Before("myPointCut()")
		public void myBefore(JoinPoint joinPoint){
			System.out.print("前置通知:模拟执行权限检查");
			System.out.print("目标类为:"+joinPoint.getTarget());
			System.out.println(",被植入增强处理的目标方法为:"+joinPoint.getSignature().getName());
		}
		//后置通知
		@AfterReturning("myPointCut()")
		public void myReturning(JoinPoint joinPoint){
			System.out.print("后置通知:模拟记录日志");
			System.out.println("被植入增强处理的目标方法为:"+joinPoint.getSignature().getName());
		}
		//环绕通知
		@Around("myPointCut()")
		public Object myAround(ProceedingJoinPoint point)throws Throwable{
			System.out.println("环绕开始:执行目标方法,模拟开启事务");
			Object obj=point.proceed();
			System.out.println("环绕结束,执行目标方法之后,模拟关闭事务");
			return obj;	
		}
		//异常通知
		@AfterThrowing(value="myPointCut()",throwing="throwable")
		public void myAfterThrowing(JoinPoint joinPoint,Throwable throwable){
			System.out.println("异常通知,错误了"+throwable.getMessage());
		}
		//最终通知
		@After("myPointCut()")
		public void myAfter(){
			System.out.println("最终通知,模拟方法结束后释放资源");
		}

}
在com.ssm.aspectj.annotation包中创建applicationContext.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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"  
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
         http://www.springframework.org/schema/context
     	http://www.springframework.org/schema/context/spring-context-4.3.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
       
	<!-- 扫描特定包,使注解生效 -->
	<context:component-scan  base-package="com.ssm"  />
	<!-- 启用基于注解的声明式AspectJ支持 -->
	<aop:aspectj-autoproxy />
</beans>
测试类TextAnnotation
package com.ssm.aspectj.annotation;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.ssm.aspectj.UserDao;

public class TextAnnotation {

	public static void main(String[] args) {
		String xmlPath="com/ssm/aspectj/annotation/applicationContext.xml";
		ApplicationContext app=new ClassPathXmlApplicationContext(xmlPath);
		UserDao userDao=(UserDao)app.getBean("userDao");
		userDao.insert();
		userDao.delete();

	}

}
三月 20, 2022 2:31:50 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@817b38: startup date [Sun Mar 20 14:31:50 CST 2022]; root of context hierarchy
三月 20, 2022 2:31:50 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [com/ssm/aspectj/annotation/applicationContext.xml]
环绕开始:执行目标方法,模拟开启事务
前置通知:模拟执行权限检查目标类为:com.ssm.aspectj.UserDaoImpl@19e68d0,被植入增强处理的目标方法为:insert
添加用户
环绕结束,执行目标方法之后,模拟关闭事务
最终通知,模拟方法结束后释放资源
后置通知:模拟记录日志被植入增强处理的目标方法为:insert
环绕开始:执行目标方法,模拟开启事务
前置通知:模拟执行权限检查目标类为:com.ssm.aspectj.UserDaoImpl@19e68d0,被植入增强处理的目标方法为:delete
删除用户
环绕结束,执行目标方法之后,模拟关闭事务
最终通知,模拟方法结束后释放资源
后置通知:模拟记录日志被植入增强处理的目标方法为:delete

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

点份炸鸡778

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值