spring-第二章-AOP
一,回顾
1.控制反转(IOC)
以前创建对象,由我们自己决定,现在我们把管理对象的声明周期权力交给spring;
2.依赖注入(DI)
A对象需要B对象的支持,spring就把B注入给A,那么A就拥有了B;
底层通过反射技术实现(Class字节码)
3.具体实现
(1)实体类
(2)把实体类注册到xml配置文件中
(3)通过context上下文对象(spring容器)获取进行使用
二,AOP简介
AOP(Aspect Oriented Programming) 面向切面编程(横向);
OOP面向对象编程(纵向编程)
AOP技术利用"横切",解刨开封装的对象内容,将那些影响了多个类的公共行为封装到一个可重用的模块,并将其命名为"Aspect",即切面,切面就是与主业务无关,却为主业务模块提供额外的扩展,便于减少系统代码的重复性,降低模块之间的耦合性,并利于系统的可操作性和维护性;
AOP底层使用代理技术实现,代理内部有反射技术的影子
三AOP基本概念
1.Aspect(切面)
通常是一个类,里面可以定义切入点和通知
2.JoinPoint(连接点)
被拦截的点,因为spring只支持方法类型的连接点,所以在spring中连接点指定就是被拦截的方法,实际上连接点还可以是字段或者构造器
3.advice(通知)
指拦截到的连接点(方法)之后要执行的增强代码,通知分为:前置,后置,异常,最终,环绕通知(before,after,afterThrowing,afterReturing,around)
4.pointcut(切入点)
对连接点(方法)进行拦截的定义,在程序主要体现为输入切入点表达式
5.tarage(目标对象)
代理的目标对象
6.proxy(代理)
AOP框架自动创建的代理对象
四,spring aop基于xml方式实现
1,添加依赖
<!-- spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.0.RELEASE</version>
</dependency> <!-- aop依赖的jar包 -->
<!-- aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<!--aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<scope>provided</scope>
</dependency>
2、UserServiceImpl业务类
public class UserServiceImpl { public boolean delete(int id){
System.out.println("UserServiceImpl.delete..."+id);
return true;
}
3、TranAop切面类
此类为切面类,给业务层类中方法添加增强代码
public class TranAop {
//前置通知
public void before(){
System.out.println("TranAop.before...");
}
//返回值后通知
public void afterReturning(){
System.out.println("TranAop.afterReturning...");
}
//异常通知
public void afterThrowing(Exception ex){
System.out.println("TranAop.afterThrowing..."+ex.getMessage());
}
//后置通知(最终)
public void after(){
System.out.println("TranAop.after...");
}
//环绕通知
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("TranAop.around.start");
Object[] args = pjp.getArgs();
Object result = null;
//try {
result = pjp.proceed();//执行目标方法
//} catch (Throwable e) {
// System.out.println("发生异常了哦:"+e.getMessage());
//}
System.out.println("TranAop.around.end");
return result;
}
}
4、beans.xml
我们需要再beans.xml中配置aop;需要在xml中添加头部schema文件引用
<?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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 声明bean -->
<bean id="user1" class="com.yujun.maven.service.UserServiceImpl"></bean>
<bean id="tranAop" class="com.yujun.maven.aop.TranAop"></bean> <!-- spring aop 配置 -->
<aop:config>
<!-- 声明切面类 id:唯一标识 ref:引用bean的id-->
<aop:aspect id="myAspect" ref="tranAop">
<!-- 声明切入点(拦截哪些方法) 拦截service包中所有类中所有方法-->
<aop:pointcut expression="execution(* com.yujun.maven.service.*.*(..))" id="myPointcut"/>
<!-- 实际开发中,下面5中通知,根据实际情况进行合理的选中,不是说像我们现在这样5种都配置 -->
<!-- 前置通知 method:切面类中的方法名-->
<aop:before method="before" pointcut-ref="myPointcut"/>
<!-- 后置通知 -->
<aop:after method="after" pointcut-ref="myPointcut"/>
<!-- 最终通知 -->
<aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
<!-- 异常通知 throwing:是切面类中方法的形参名-->
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointcut" throwing="ex"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="myPointcut"/>
</aop:aspect> </aop:config> </beans>
5、测试
public class Demo1 { public static void main(String[] args) {
//context上下文
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl bean = context.getBean("user1", UserServiceImpl.class);
bean.delete(10);
运行后的控制台输出结果:
TranAop.before...
TranAop.around.start
UserServiceImpl.delete...10
TranAop.around.end
TranAop.afterReturning...
TranAop.after...
可以看到在目标方法UserServiceImpl.delete的前后有额外的输出语句,也就表名之前我们的aop配置生效;
这里没有看到有关于异常通知的输出,原因是我们目标方法delete没有发生异常,所以就不会执行异常通知;
若想看到异常通知被执行,只需要在目标方法中添加一个可以触发异常的语句即可,当前前提是我们的环绕通知中没有对目标方法进行异常处理;
五,springaop基于注解的方式实现
下面我们使用注解方式来实现aop技术,相对来说注解方式比xml配置更简洁,所以现在实际开发中我们都会优先考虑使用注解方式;
1、AserviceImpl业务类
业务类,我们通常会统一放在service包中;
public class AServiceImpl { public int m1(String s){
System.out.println("AServiceImpl.m1..."+s);
return 100;
} }
2、LogAop切面类
//组件:会把当前类当做bean注册到spring容器中,等效于xml中<bean />
@Component
//切面类:等效于xml中的<aop:aspect />
@Aspect
public class LogAop {
//切入点(拦截哪些类中的哪些方法):等效于xml中<aop:pointcut />
@Pointcut("execution(* com.yujun.maven.service.*.*(..))")
private void pointCut(){ }
//前置通知:等效于xml中<aop:before />,里面的pointCut()字符串是本类中的切入点方法
@Before("pointCut()")
public void before(){
System.out.println("LogAop.before...");
}
//返回通知:等效于xml中<aop:after-returning />
@AfterReturning(pointcut="pointCut()",returning="result")
public void afterReturning(Object result){
System.out.println("LogAop.afterReturning..."+result);
}
//异常通知:等效于xml中<aop:after-throwing />
@AfterThrowing(pointcut="pointCut()",throwing="ex")
public void afterThrowing(Exception ex){
System.out.println("LogAop.afterThrowing..."+ex.getMessage());
}
//最终通知:等效于xml中<aop:after />
@After("pointCut()")
public void after(){
System.out.println("LogAop.after...");
}
//环绕通知:等效于xml中<aop:around />
@Around("pointCut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("LogAop.around.start...");
Object result = pjp.proceed();//执行目标方法
System.out.println("LogAop.around.end..."+result);
return result;
}
}
此类中我们使用很多注解,每个注解的含义都有详细的说明,这里就不多做额外的解释;
主要说一下@Component注解,次注解是spring的基础注解,被此注解标注的类会被当做组件注册到spring容器中,也就相当于之前我们在xml中配置<bean />,也就是说只要在类上标注此注解,我们就不用像之前一样在xml中使用<bean />标签注册实例了;
3、beans-anno.xml
此xml配置文件我们需要添加context的schema文件头引用
<?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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 开启扫描包:把base-package指定的包中的类中的组件注册到spring容器中-->
<context:component-scan base-package="com.yujun.maven.aop"/> <!-- 为 @AspectJ标注的类提供代理-->
<aop:aspectj-autoproxy/>
</beans>
<context:component-scan />标签配置的作用就是开启扫包功能,它会扫描base-package属性中指定的包中所有类,然后把类上标注有@Component, @Repository, @Service, @Controller, @RestController, @ControllerAdvice, @Configuration等注解的类注册添加到spring容器中;
<aop:aspectj-autoproxy/>标签则是为使用@AspectJ注解风格的切面类提供代理,若没有此配置,我们的目标方法时没有aop技术支持的
4、@Service注解
//组件:业务逻辑层的组件,等效于<bean />
@Service
public class AServiceImpl { public int m1(String s){
System.out.println("AServiceImpl.m1..."+s);
return 100;
} }
对于AserviceImpl业务类,我们之前是通过在xml中配置<bean />标签来注册实例,那么这里我们还可以选择使用@Service注解,此注解标注的类会被当做一个服务性质组件实例被注册到spring容器中,等效于xml中<bean />标签配置实例;
注意的是我们还需要在bean-anno.xml中新增一个扫包器,因为此业务类在service包中;
<context:component-scan base-package="com.yujun.maven.service"/>
5、测试
public class Demo2 { public static void main(String[] args) {
//context上下文
ApplicationContext context = new ClassPathXmlApplicationContext("beans-anno.xml");
AServiceImpl a1 = context.getBean(AServiceImpl.class);
a1.m1("admin");
} }
运行之后控制台输出
LogAop.around.start...
LogAop.before...
AServiceImpl.m1...admin
LogAop.around.end...100
LogAop.after...
LogAop.afterReturning...100
可以看到我们注解版的aop技术已经成功实现,就是输出的语句顺序和执行xml方法稍微不同,但是最终的功能实现是没有差别的;
六、小结
对于上述的两种方式aop实现,需要自己下来多多测试,然后认真理解其执行流程,这样才能对aop面向切面技术有一个更深的理解和认识;
在aop注解版方式中,我们介绍的@Component和@Service两个注解以及 xml配置中的<context:component-scan />标签扫描器,我们在后面章节也就着重说明;
spring-第二章-AOP的更多相关文章
- 复习Spring第二课--AOP原理及其实现方式
AOP原理: AOP,面向方面的编程,使用AOP,你可以将处理方面(Aspect)的代码注入主程序,通常主程序的主要目的并不在于处理这些aspect.AOP可以防止代码混乱.AOP的应用范围包括:持久 ...
- Spring 3.x 实践 第一个例子(Spring 3.x 企业应用开发实战读书笔记第二章)
前言:工作之后一直在搞android,现在需要更多和后台的人员交涉,技术栈不一样,难免鸡同鸭讲,所以稍稍学习下. 这个例子取自于<Spring 3.x 企业应用开发实战>一书中的第二章,I ...
- Java开发工程师(Web方向) - 04.Spring框架 - 第3章.AOP技术
第3章--AOP技术 Spring框架 - AOP概述 笔记https://my.oschina.net/hava/blog/758873Spring框架 - AOP使用 笔记https://my.o ...
- #Spring实战第二章学习笔记————装配Bean
Spring实战第二章学习笔记----装配Bean 创建应用对象之间协作关系的行为通常称为装配(wiring).这也是依赖注入(DI)的本质. Spring配置的可选方案 当描述bean如何被装配时, ...
- Spring学习指南-第二章-Spring框架基础(完)
第二章 Spring框架基础 面向接口编程的设计方法 在上一章中,我们看到了一个依赖于其他类的POJO类包含了对其依赖项的具体类的引用.例如,FixedDepositController 类包含 ...
- 第05章 AOP细节
第05章 AOP细节 1.切入点表达式 1.1 作用 通过表达式的方式定位一个或多个具体的连接点. 1.2 语法细节 ①切入点表达式的语法格式 execution([权限修饰符] [返回值类型] [简 ...
- Spring官网阅读(十八)Spring中的AOP
文章目录 什么是AOP AOP中的核心概念 切面 连接点 通知 切点 引入 目标对象 代理对象 织入 Spring中如何使用AOP 1.开启AOP 2.申明切面 3.申明切点 切点表达式 excecu ...
- 《精通Spring4.x企业应用开发实战》第二章
昨天联系了一下学长,学长说这个项目因为种种原因代码比较混乱,感觉最坏的打算是从头开始写. 大概询问了一下学长和xianhua学姐的建议,又看了看网上的资料,这个项目开发的技术栈基本就是SpringBo ...
- Spring框架之AOP源码完全解析
Spring框架之AOP源码完全解析 Spring可以说是Java企业开发里最重要的技术.Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Orie ...
- Spring 3.0 AOP (一)AOP 术语
关于AOP.之前我已写过一个系列的随笔: <自己实现简单的AOP>,它的关注点在于实现.实现语言是C#,实现方式为 自定义实现 RealProxy 抽象类.重写Invoke方法,以便进行方 ...
随机推荐
- kubernetes role
https://kubernetes.io/docs/admin/authorization/rbac/
- Linux实战教学笔记31:Keepalived高可用集群应用实践
1.1 Keepalived高可用软件 1.1.1 Keepalived介绍 Keepalived软件起初是专门为LVS负载均衡软件设计的,用来管理并监控LVS集群系统中各个服务节点的状态,后来又加入 ...
- partial分部类
意义 1.源代码控制 2.将一个类或结构分成不同的逻辑单元 3.代码拆分
- Apache Hive (六)Hive SQL之数据类型和存储格式
转自:https://www.cnblogs.com/qingyunzong/p/8733924.html 一.数据类型 1.基本数据类型 Hive 支持关系型数据中大多数基本数据类型 类型 描述 示 ...
- CSS的编写规范
一.前言 如上图,页面在渲染和画图时,耗时还是比较多的,这就对我们的编写要求愈加严格. 我们有很多方法来减少上图所示的页面加载耗时的,比如 但是更多的还是在于平时的编写规范,我们需要了解浏览器,让他更 ...
- Spring中Aspect的切入点的表达式定义细节
用过很多次切面aspect了,对于表达式总是记得很模糊,今天总结一下. 1.切面做如下设置则只会拦截返回值为String类型的方法 @Aspect public class MyInterceptor ...
- 获取时间【NSDate】
[Objective-C]NSDate详解及获取当前时间等常用操作 博客分类: Objective-C objective-cnsdate NSDate类用于保存时间值,同时提供了一些方法来处理一些 ...
- jquery入门 动态调整div大小,使其宽度始终为浏览器宽度
有时候我们需要设置宽度为整个浏览器宽度的div,当然我们可以使用相对布局的方式做到这一点,不过我们也可以用jquery来实现. <!doctype html> <html> & ...
- STM32 FATFS文件系统移植
http://www.360doc.com/content/11/1221/10/7736891_173820469.shtml
- jedis的publish/subscribe[转]含有redis源码解析
首先使用redis客户端来进行publish与subscribe的功能是否能够正常运行. 打开redis服务器 [root@localhost ~]# redis-server /opt/redis- ...