SSM学习笔记三:Spring框架技术(上)

主要内容:基本概念、Spring与IOC、Spring与AOP

一、Spring概述

根据功能的不同,可以将一个系统中的代码分为主业务逻辑与系统级业务逻辑;Spring的主要作用就是为系统代码进行“解耦”,使得主业务逻辑与系统级业务逻辑代码分离,降低代码间的耦合度,而控制反转IOC与面向切面编程AOP就是Spring降低耦合度的方式,也是Spring的核心。

1.1 Spring体系结构

在这里插入图片描述

1.2 Spring特点

1.2.1 非侵入式

非侵入式是指Spring框架的API不会在业务逻辑上出现,即业务逻辑是简单的java类,因此,业务逻辑可以从Spring框架快速的移植到其它框架,与环境无关。

1.2.2 容器

Spring是作为一个容器,既可管理对象的生命周期、对象与对象之间的依赖关系;同时也可以通过配置文件来定义对象,设置对象间的依赖关系。

1.2.3 IOC

IOC(Inversion of control),即控制反转。控制反转是一种编程思想,在Spring中的体现是创建被调用的实例不是由调用者完成,而是由Spring容器完成,并自动“注入”给调用者。

1.2.4 AOP

AOP(Aspect Orient Programming),即面向切面编程。面向切面编程也是一种编程思想。我们可以把日志、安全、事务管理等系统级服务看成一个“切面”,Sprin在开发时将主业务逻辑与系统级业务逻辑进行分离,从而实现解耦。当主业务逻辑需要用到系统级业务逻辑时,直接将“切面”动态的织入到主业务逻辑中。

二、Spring与IOC

控制反转就是将控制对象权从代码本身反转到外部容器。IOC是一种编程思想,其实现方式有很多,当前比较流行的有依赖注入(DI, Dependency Injection)和依赖查找,而依赖注入方式应用的更为广泛。
依赖注入DI是指程序运行过程中,若需要调用另一个对象协助时,无须在代码中创建被调用者,而是依赖于外部容器,由外部容器创建后传递给程序。依赖注入让Spring的Bean之间以配置文件的方式组织在一起,实现了解耦合。

2.1 Spring基本程序的开发过程

2.1.1 导入Jar包

在这里插入图片描述

2.1.2 定义接口与实体类

2.1.3 创建Spring配置文件,注册bean元素

在这里插入图片描述
<bean/>用于定义一个实例对象,一个实例对应一个bean元素。

2.1.4 定义测试类

在这里插入图片描述

2.2 Spring容器

由上述测试类可知,Spring的对象要从容器中获取,那么获取容器是第一步。能够在程序中充当容器的有两种:ApplicationContext接口容器和BeanFactory接口容器。

2.2.1 ApplicationContext接口容器

根据Spring配置文件位置的不同,获取容器的方式有三种
在这里插入图片描述

2.2.2 BeanFactory接口容器

BeanFactory接口是ApplicationContext接口的父类,若要创建BeanFactory容器,需要先使用其实现类XmlBeanFactory。
在这里插入图片描述

2.2.3 两个接口容器的区别

虽然这两个接口容器所要加载的Spring配置文件是同一个文件,但在代码中的这两个容器对象却不是同一个对象,即不是同一个容器:它们对于容器内对象的装配(创建)时机是不同的。

ApplicationContext容器中对象的装配时机:在容器对象初始化时,将其中的所有对象一次性全部装配好
BeanFactory容器中对象的装配时机:容器中对象的装配与加载采用延迟加载策略,即在第一次调用getBean()时,才真正装配该对象。

2.3 Bean的装配

Bean的装配,即Bean对象的创建,容器根据代码要求创建Bean对象后再传递给代码的过程,称为Bean的装配。

2.3.1 默认装配

以上示例均属于默认装配,即代码通过getBean()方式直接从容器获取指定的Bean实例。装配时,容器会调用Bean类的无参构造器,创建空值的实例对象。

2.3.2 工厂模式之动态工厂Bean

有些时候,项目中会通过工厂类来创建Bean实例,而不像前面例子,直接由Spring容器来装配Bean实例。使用工厂模式创建Bean实例的缺点是会使工厂类与要创建的Bean类耦合到一起。

a、将动态工厂Bean作为普通Bean使用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这样做的缺点是,不仅工厂类与目标类耦合到了一起,测试类与工厂类也耦合到了一起。

b、使用Spring的动态工厂Bean

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2.3 工厂模式之静态工厂Bean

静态工厂无需工厂实例,所以不再需要定义静态工厂<bean/>。而对于工厂所要创建的Bean是由工厂类创建的,所以需要指定所用工厂类,故class属性指定的是工厂类而非自己的类。当然,还需要通过factory-method属性指定工厂方法。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2.4 容器中Bean的作用域

当通过Spring容器创建一个Bean实例时,不仅可以完成Bean的实例化,还可以通过scope属性,为Bean指定特定的作用域。

Spring支持5种作用域:singleton:单态模式、prototype:原型模式、request、session、global session

a、request、session与global session,只有在Web应用中使用Spring时,该作用域才有效。

b、对于scope为singleton的单例模式,该Bean是在容器被创建时即被装配好了,是单例的,只有一个实例。

c、对于scope为prototype的原型模式,Bean实例是在代码中使用该Bean实例时才进行装配的,即每次使用getBean方法获取的同一个的实例都是一个新的实例。
在这里插入图片描述

2.2.5 Bean后处理器

Bean后处理器是一种特殊的Bean。
代码中首先需要自定义Bean后处理器类,该类就是实现了接口BeanPostProcessor的类。该接口中包含两个方法,postProcessBeforeInitialization和postProcessAfterInitialization,分别在目标Bean初始化完毕之前与之后执行,它们的返回值为:功能被扩展或增强后的Bean对象。容器中所有的Bean在初始化时,均会自动执行该类的两个方法。

a、定义后处理器类

在这里插入图片描述
在这里插入图片描述

b、修改Spring配置文件(创建Bean标签)

在这里插入图片描述

2.2.6 定制Bean的生命始末行为

可以为Bean定制初始化后的生命行为,也可以为Bean定制销毁前的生命行为。

步骤:

a、在Bean类中定义好行为方法
b、在配置文件的标签中增加属性

在这里插入图片描述
注意,若要看到Bean的destroy-method的执行结果,需要满足两个条件:Bean为singleton,即单例;要确保容器关闭。

2.3 基于XML的DI

Bean实例在装配后,就要对Bean对象的属性进行初始化。初始化是由容器自动完成的,称为注入。根据注入方式的不同,常用的有两类:设值注入、构造注入。(主要使用设值注入)

设值注入:通过setter方法传入被调用者的实例。这种注入方式简单、直观,因而在Spring的依赖注入中大量使用。
构造注入:在构造调用者实例的同时,完成被调用者的实例化。即使用构造器设置依赖关系。

2.3.1 集合属性的注入

举例说明:
在这里插入图片描述

a、为数组注入值

在这里插入图片描述

b、为List注入值

在这里插入图片描述

c、为Set注入值

在这里插入图片描述

d、为Map注入值

在这里插入图片描述

e、为Properties注入值

在这里插入图片描述

2.3.2 域属性的自动注入

对于域属性的注入,可以通过为<bean/>标签设置autowire属性值,为域属性进行隐式自动注入。根据自动注入判断标准的不同,可以分为两种:byName(根据名称自动注入)和byType:(根据类型自动注入)

a、byName方式自动注入

在这里插入图片描述
在这里插入图片描述

b、byType方式自动注入

在这里插入图片描述
在这里插入图片描述

2.3.3 使用SPEL注入

SPEL,Spring Expression Language,即Spring EL表达式语言。在Spring配置文件中为Bean的属性注入值时,可直接使用SPEL表达式计算的结果。SPEL表达式以#开头,后跟一对大括号。

2.3.4 使用内部Bean注入

若注册了某个bean(如上school),它会被调用者bean使用(如上student),但不希望在代码中通过getBean方法被获取, 则可将该Bean的定义放入调用者bean定义的内部。
在这里插入图片描述

2.3.5 使用同类抽象Bean注入

当若干Bean实例同属于一个类,且这些实例的属性值又有相同值时,可以使用抽象Bean,以简化配置文件。
在这里插入图片描述
在这里插入图片描述

2.3.6 使用异类抽象Bean注入

当若干不同的类对象具有相同的属性,且其值也相同时,可使用异类抽象Bean。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3.7 为应用指定多个Spring配置文件

在实际应用里,随着应用规模的增加,系统中Bean数量也大量增加,导致配置文件变得非常庞大、臃肿。为了避免这种情况的产生,提高配置文件的可读性与可维护性,可以将Spring配置文件分解成多个配置文件。

a、平等关系的配置文件

在这里插入图片描述

b、包含关系的配置文件

总配置文件将各其它子文件通过<import/>引入。在类中仅需要导入总配置文件。
在这里插入图片描述

2.4 基于注解的DI

对于DI使用注解,将不再需要在Spring配置文件中声明Bean实例。
Spring中使用注解,需要在原有Spring运行环境基础上再做一些改变,完成以下三个步骤:
a、导入AOP的Jar包
b、需要更换配置文件头,即添加相应的约束
c、需要在Spring配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。

2.4.1 定义Bean --@Component

要注册一个bean,需要在类上使用注解@Component,该注解的value属性用于指定该bean的id值。
在这里插入图片描述
Spring还提供了3个功能基本和@Component等效的注解:@Repository、@Service、@Controller

2.4.2 Bean的作用域 --@Scope

指定作用域需要在类上使用注解@Scope,其value属性用于指定作用域。默认为singleton。
在这里插入图片描述

2.4.3 基本类型属性注入 --@Value

基本属性注入需要在属性上使用注解@Value,该注解的value属性用于指定要注入的值。使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上。
在这里插入图片描述

2.4.4 域属性注入之传统注解

a、按类型注入域属性 --@Autowired

域属性按类型注入需要在域属性上使用注解@Autowired,该注解默认使用按类型自动装配Bean的方式。使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上。
在这里插入图片描述
在这里插入图片描述

b、按名称注入域属性 --@Autowired与@Qualifier

域属性按名称注入需要在域属性上联合使用注解@Autowired与@Qualifier。@Qualifier的value属性用于指定要匹配的Bean的id值。同样类中无需setter,也可加到setter上。
在这里插入图片描述
在这里插入图片描述

2.4.5 域属性注入之标准注解 --@Resource

Spring提供了对JSR-250规范中定义@Resource标准注解的支持。@Resource注解既可以按名称匹配Bean,也可以按类型匹配Bean。使用该注解,要求JDK必须是6及以上版本。

a、按类型注入域属性

@Resource注解若不带任何参数,则会按照类型进行Bean的匹配注入。
在这里插入图片描述

b、按名称注入域属性

@Resource注解指定其name属性,则name的值即为按照名称进行匹配的Bean的id。
在这里插入图片描述

2.4.6 Bean的生命始末 --@PostConstruct与@PreDestroy

在方法上使用@PostConstruct,与原来的init-method等效。在方法上使用@PreDestroy,与destroy-method等效。
在这里插入图片描述

2.4.7 使用JavaConfig进行配置(了解)

JavaConfig,是在Spring 3.0开始从一个独立的项目并入到Spring中的。JavaConfig可以看成一个用于完成Bean装配的Spring配置文件,即Spring容器,只不过该容器不是XML文件,而是由程序员使用Java自己编写的Java类。

2.5 注解与XML共同使用

注解的好处是,配置方便,直观。但其弊端也显而易见:以硬编码的方式写入到了Java代码中,其修改是需要重新编译代码的。
XML配置方式的最大好处是,对其所做修改,无需编译代码,只需重启服务器即可将新的配置加载。

若注解与XML同用,XML的优先级要高于注解。这样做的好处是,需要对某个Bean做修改,只需修改配置文件即可。当然,此时,Bean类要有setter或构造器。

三、Spring与AOP

3.1 AOP概述

3.1.1 简介

AOP(Aspect Orient Programming),即面向切面编程。

我们的代码一般会分为主业务逻辑代码和交叉业务逻辑代码。所谓交叉业务逻辑是指,通用的、与主业务逻辑无关的代码,往往存在重复性,如安全检查、事务、日志等。面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP容器的功能将切面织入到主业务逻辑中。

若不使用AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样,会使主业务逻辑变的混杂不清。

3.1.2 AOP编程术语

a、切面(Aspect)

切面泛指交叉业务逻辑。上例中的事务处理、日志处理就可以理解为切面。

b、织入(Weaving)

织入是指将切面代码插入到目标对象的过程。

c、连接点(JoinPoint)

连接点指可以被切面织入的方法。通常业务接口中的方法均为连接点。

d、切入点(Pointcut)

切入点指切面具体织入的方法。在StudentServiceImpl类中,若doSome()将被增强,而doOther()不被增强,则doSome()为切入点,而doOther()仅为连接点。
被标记为final的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不能被增强的。

e、目标对象(Target)

目标对象指将要被增强的对象。即包含主业务逻辑的类的对象。

f、通知(Advice)

通知是切面的一种实现,可以完成简单织入功能(织入功能就是在这里完成的)。通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。

切入点定义切入的位置,通知定义切入的时间。

g、顾问(Advisor)

顾问是切面的另一种实现,能够将通知以更为复杂的方式织入到目标对象中,是将通知包装为更复杂切面的装配器。

3.2 通知(Advice)

3.2.1 通知的使用步骤

a、定义目标类

定义目标类,就是定义之前的普通Bean类,也就是即将被增强的Bean类。

b、定义通知类

通知类是指,实现了相应通知类型接口的类。当前,实现了这些接口,就要实现这些接口中的方法,而这些方法的执行,则是根据不同类型的通知,其执行时机不同。
通知分为:前置通知、后置通知、环绕通知、异常处理通知

c、注册目标类

在这里插入图片描述

d、注册通知切面

在这里插入图片描述

e、注册代理工厂Bean类对象ProxyFactoryBean

这里的代理使用的是ProxyFactoryBean类。代理对象的配置,是与JDK的Proxy代理参
数是一致的,都需要指定三部分:目标类,接口,切面。
在这里插入图片描述

f、客户端访问动态代理对象

客户端访问的是动态代理对象,而非原目标对象。因为代理对象可以将交叉业务逻辑按照通知类型,动态的织入到目标对象的执行中。

3.2.2 通知详解

a、前置通知MethodBeforeAdvice

定义前置通知,需要实现MethodBeforeAdvice接口。该接口中有一个方法before(),会在目标方法执行之前执行。
在这里插入图片描述

b、后置通知AfterReturningAdvice

定义后置通知,需要实现接口AfterReturningAdvice。该接口中有一个方法afterReturning(),会在目标方法执行之后执行。
在这里插入图片描述

c、环绕通知MethodInterceptor

定义环绕通知,需要实现MethodInterceptor接口。环绕通知,也叫方法拦截器,可以在目标方法调用之前及之后做处理,可以改变目标方法的返回值,也可以改变程序执行流程。
在这里插入图片描述

d、异常通知ThrowsAdvice

定义异常通知,需要实现ThrowsAdvice接口。该接口的主要作用是,在目标方法抛出异常后,根据异常的不同做出相应的处理。当该接口处理完异常后,会简单地将异常再次抛出给目标方法。
在这里插入图片描述

3.2.3 通知的其他方法

a、给目标方法织入多个切面

若要给目标方法织入多个切面,则需要在配置代理对象的切面属性时,设定为list。
在这里插入图片描述

b、无接口的CGLIB代理生成

若不存在接口,则ProxyFactoryBean会自动采用CGLIB方式生成动态代理。
在这里插入图片描述

c、有接口的CGLIB代理生成proxyTargetClass属性

若存在接口,但又需要使用CGLIB生成代理对象,此时,只需要在配置文件中增加一个proxyTargetClass属性设置,用于指定强制使用CGLIB代理机制。
在这里插入图片描述

3.3 顾问(Advisor)

通知(Advice)是Spring提供的一种切面(Aspect)。但其功能过于简单:只能将切面织入到目标类的所有目标方法中,无法完成将切面织入到指定目标方法中。

顾问(Advisor)是Spring提供的另一种切面。顾问将通知进行了包装,会根据不同的通知类型,在不同的时间点,将切面织入到不同的切入点。其可以完成更为复杂的切面织入功能。PointcutAdvisor是顾问的一种,可以指定具体的切入点。

PointcutAdvisor接口有两个较为常用的实现类:NameMatchMethodPointcutAdvisor名称匹配方法切入点顾问;RegexpMethodPointcutAdvisor正则表达式匹配方法切入点顾问(仅介绍前者)

3.3.1 名称匹配方法切入点顾问

NameMatchMethodPointcutAdvisor,即名称匹配方法切入点顾问。容器可根据配置文件中指定的方法名来设置切入点。代码不用修改,只在配置文件中注册一个顾问,然后使用通知属性advice与切入点的方法名mappedName对其进行配置。代理中的切面,使用这个顾问即可。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.4 自动代理生成器

前面代码中所使用的代理对象,均是由ProxyFactoryBean代理工具类生成的。而该代理工具类存在着如下缺点:(1)一个代理对象只能代理一个Bean,即如果有两个Bean同时都要织入同一个切面,这时,不仅要配置这两个Bean,即两个目标对象,同时还要配置两个代理对象。(2)在客户类中获取Bean时,使用的是代理类的id,而非我们定义的目标对象Bean的id。我们真正想要执行的应该是目标对象。从形式上看,不符合正常的逻辑。

Spring提供了自动代理生成器,用于解决ProxyFactoryBean的问题。常用的自动代理生成器有两个:默认advisor自动代理生成器和Bean名称自动代理生成器。

3.4.1 默认advisor自动代理生成器

DefaultAdvisorAutoProxyCreator代理的生成方式是,将所有的目标对象与Advisor自动结合,生成代理对象。无需给生成器做任何的注入配置。
在这里插入图片描述
DefaultAdvisorAutoProxyCreator会为每一个目标对象织入所有匹配的Advisor,不具有选择性,且切面只能是顾问Advisor。

3.4.2 Bean名称自动代理生成器

BeanNameAutoProxyCreator的代理生成方式是,根据bean的id,来为符合相应名称的类生成相应代理对象,且切面既可以是顾问Advisor又可以是通知Advice。
在这里插图片描述
beanNames:指定要增强的目标类的id
interceptorNames:指定切面。可以是顾问Advisor,也可以是通知Advice。
在这里插入图片描述

3.5 AspectJ对AOP的实现

3.5.1 AspectJ简介

AspectJAspectJ是一个面向切面的框架,也实现了AOP的功能,且其实现方式更为简捷,使用更为方便,而且还支持注解式开发。
所以,Spring又将AspectJ的对于AOP的实现也引入到了自己的框架中。在Spring中使用AOP开发时,一般使用AspectJ的实现方式。

3.5.2 AspectJ的通知类型

AspectJ中常用的通知有五种类型:前置通知;后置通知;环绕通知;异常通知;最终通知。其中最终通知是指,无论程序执行是否正常,该通知都会执行。类似于try…catch中的finally代码块。

3.5.3 AspectJ的切入点表达式

AspectJ除了提供了六种通知外,还定义了专门的表达式用于指定切入点。表达式的原型是:
execution (
[modifiers-pattern] 访问权限类型
ret-type-pattern 返回值类型
[declaring-type-pattern] 全限定性类名
name-pattern(param-pattern) 方法名(参数名)
[throws-pattern] 抛出异常类型
)
表达式中加[ ]的部分表示可省略部分,各部分间用空格分开。

3.5.4 AspectJ的开发环境

a、导入两个Jar包
b、引入AOP约束

3.5.5 AspectJ基于注解的AOP实现

a、实现步骤

Step1:定义业务接口与实现类
在这里插入图片描述
在这里插入图片描述
Step2:定义切面POJO类
在这里插入图片描述
Step3:在切面类上添加@Aspect注解
在这里插入图片描述
Step4:在POJO类的普通方法上添加通知注解
在这里插入图片描述
Step5:注册目标对象与POJO切面类
在这里插入图片描述
Step6:注册AspectJ的自动代理
在这里插入图片描述
Step7:测试类中使用目标对象的id

b、@Before前置通知 --增强方法有JoinPoint参数
c、@AfterReturning后置通知 --注解有returning属性
d、@Around环绕通知 --增强方法有ProceedingJoinPoint参数
e、@AfterThrowing异常通知 --注解中有throwing属性
f、@After最终通知

3.5.6 AspectJ基于XML的AOP实现

a、实现步骤

Step1:定义业务接口与实现类
Step2:定义切面POJO类
Step3:注册目标对象与POJO切面类
Step4:在容器中定义AOP配置
在这里插入图片描述
Step5:测试类中使用目标对象的id

b、<aop:before/>前置通知
c、<aop:after-returning/>后置通知
d、<aop:around/>环绕通知
e、<aop:after-throwing/>异常通知
f、<aop:after/>最终通知
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值