一,回顾

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的更多相关文章

  1. 复习Spring第二课--AOP原理及其实现方式

    AOP原理: AOP,面向方面的编程,使用AOP,你可以将处理方面(Aspect)的代码注入主程序,通常主程序的主要目的并不在于处理这些aspect.AOP可以防止代码混乱.AOP的应用范围包括:持久 ...

  2. Spring 3.x 实践 第一个例子(Spring 3.x 企业应用开发实战读书笔记第二章)

    前言:工作之后一直在搞android,现在需要更多和后台的人员交涉,技术栈不一样,难免鸡同鸭讲,所以稍稍学习下. 这个例子取自于<Spring 3.x 企业应用开发实战>一书中的第二章,I ...

  3. Java开发工程师(Web方向) - 04.Spring框架 - 第3章.AOP技术

    第3章--AOP技术 Spring框架 - AOP概述 笔记https://my.oschina.net/hava/blog/758873Spring框架 - AOP使用 笔记https://my.o ...

  4. #Spring实战第二章学习笔记————装配Bean

    Spring实战第二章学习笔记----装配Bean 创建应用对象之间协作关系的行为通常称为装配(wiring).这也是依赖注入(DI)的本质. Spring配置的可选方案 当描述bean如何被装配时, ...

  5. Spring学习指南-第二章-Spring框架基础(完)

    第二章 Spring框架基础 面向接口编程的设计方法 ​ 在上一章中,我们看到了一个依赖于其他类的POJO类包含了对其依赖项的具体类的引用.例如,FixedDepositController 类包含 ...

  6. 第05章 AOP细节

    第05章 AOP细节 1.切入点表达式 1.1 作用 通过表达式的方式定位一个或多个具体的连接点. 1.2 语法细节 ①切入点表达式的语法格式 execution([权限修饰符] [返回值类型] [简 ...

  7. Spring官网阅读(十八)Spring中的AOP

    文章目录 什么是AOP AOP中的核心概念 切面 连接点 通知 切点 引入 目标对象 代理对象 织入 Spring中如何使用AOP 1.开启AOP 2.申明切面 3.申明切点 切点表达式 excecu ...

  8. 《精通Spring4.x企业应用开发实战》第二章

    昨天联系了一下学长,学长说这个项目因为种种原因代码比较混乱,感觉最坏的打算是从头开始写. 大概询问了一下学长和xianhua学姐的建议,又看了看网上的资料,这个项目开发的技术栈基本就是SpringBo ...

  9. Spring框架之AOP源码完全解析

    Spring框架之AOP源码完全解析 Spring可以说是Java企业开发里最重要的技术.Spring两大核心IOC(Inversion of Control控制反转)和AOP(Aspect Orie ...

  10. Spring 3.0 AOP (一)AOP 术语

    关于AOP.之前我已写过一个系列的随笔: <自己实现简单的AOP>,它的关注点在于实现.实现语言是C#,实现方式为 自定义实现 RealProxy 抽象类.重写Invoke方法,以便进行方 ...

随机推荐

  1. python+Django创建第一个项目

    1.首先搭建好环境 1.1 安装pyhton,Linux系统中,python是系统自带的所以就不用安装 1.2 安装Django框架 使用pip安装: pip install django 1.3 检 ...

  2. 【Todo】Linux进程调度算法学习

    参考这篇文章 http://blog.chinaunix.net/uid-27052262-id-3239260.html Linux支持三种进程调度策略,分别是SCHED_FIFO . SCHED_ ...

  3. CSS的编写规范

    一.前言 如上图,页面在渲染和画图时,耗时还是比较多的,这就对我们的编写要求愈加严格. 我们有很多方法来减少上图所示的页面加载耗时的,比如 但是更多的还是在于平时的编写规范,我们需要了解浏览器,让他更 ...

  4. jmeter-plugins-dubbo & DevToolBox

    jmeter-plugins-dubbo使用 A. 下载jmeter并安装,http://jmeter.apache.org/download_jmeter.cgi(文中使用的版本是3.3,理论上高版 ...

  5. 第一个Django应用程序_part3

    一.概述 此文延续第一个Django应用程序part2. 官方文档:https://docs.djangoproject.com/en/1.11/intro/tutorial03/ view是Djan ...

  6. Qt webkitwidgets模块和webenginewidgets模块

    问题 将Qt开发的程序从Qt5.5或更低的版本迁移到5.6或更高的版本时,会提示webkitwidgets是unknown module. Project ERROR: Unknown module( ...

  7. static_cast, dynamic_cast, reinterpret_cast, const_cast区别比较

    隐式转换(implicit conversion) ; int b; b=a; short是两字节,int是四字节,由short型转成int型是宽化转换(bit位数增多),编译器没有warning,如 ...

  8. 清北学堂 day6 兔子

    ---恢复内容开始--- [问题描述] 在一片草原上有N个兔子窝,每个窝里住着一只兔子,有M条路径连接这些窝.更特殊地是,至多只有一个兔子窝有3条或更多的路径与它相连,其它的兔子窝只有1条或2条路径与 ...

  9. vs2015 debugger,unable to attach to application iisexpress.exe

    vs2015 unable to attach to application iisexpress.exe,没有可用的数据了 搞了一天也没解决...

  10. CALayer, CoreGraphics与CABasicAnimation介绍

    今天我们来看一下CALayer.CoreGraphics和CABasicAnimation.这些东西在处理界面绘制.动画效果上非常有用. 本篇博文就讲介绍CALayer的基本概念,使用CoreGrap ...