Spring学习

技术体系架构

单一架构:一个项目一个工程,导出为一个war包,在一个tomcat上运行,也叫all in one。主要技术框架为Spring,SpringMVC,Mybatis

分布式架构:一个项目拆分成多个模块,每个模块是一个IDEA中的一个moudle,每个工程运行在自己的Tomcat上,模块间可以互相调用,每个模块内部都可以看成是一个单一架构的应用。主要技术框架为SpringBoot(SSM),SpringCloud,中间件等

框架式一个集成了基本结构、规范、设计模式、编程语言和程序库等基础组件的软件系统。

使用框架的优点:提高开发效率、降低开发成本、提高应用程序稳定性、提供标准化的解决方案

使用框架的缺点:学习成本高、可能存在局限性(应用需求超过架构范围)、版本变更和兼容性问题、架构风险(开发者可能出现设计和架构缺陷)

框架实际上就是jar包+配置文件

广义的Spring是以Spring Framework为基础的Spring全家桶;狭义的Spring是Spring Framework

Spring Framework的优势:生态系统丰富、模块化设计、简化java开发、不断创新和发展

SpringIoC容器

组件管理

Spring充当组件管理的角色,Spring框架代替了原有程序员new对象和对象赋值动作

我们只需要编写元数据(配置文件)告知Spring管理哪些类组件和他们的关系即可

组件实质就是可以复用的java对象。

组件一定是对象,但对象不一定是组件,需要对象满足可复用的原则

优势:降低了组件之间的耦合性、提高了代码的可复用性和可维护性、方便了配置和管理、交给Spring管理的对象可以享受Spring框架的其他功能,如AOP声明事务管理等

容器

普通容器:仅做存储,如数组、集合等

复杂容器:从全生命周期管理组件,不仅存储组件,还管理组件之间的依赖关系,并且创建和销毁组件。

SpringIoC容器通过配置元数据获取有关实例化、配置和组装组件的指令。配置元数据以XML、java注释或java代码形式表现。

SpringIoC容器由接口和实现类组成

容器接口:BeanFactory:提供了一种高级配置机制,能管理任何类型对象

                  ApplicationContext:是BeanFactory的子接口,扩展了一些功能

容器实现类:ClassPathXmlApplicationContext

                      FileSystemXmlApplicationContext

                      WebApplicationContext

                      AnnotationConfigApplicationContext

IoC控制反转

将控制权从应用程序转移到IoC容器中

在IoC容器中完成对象实例化

DI依赖注入

通过配置文件或注解方式,由IoC容器对象进行依赖注入

三种注入方式:构造函数注入、Setter方法注入和接口注入

IoC实现

1.编写配置信息

2.实例化IoC对象并指定配置信息

3.在java代码中使用getBean获取组件并使用

4.close销毁容器

实例化对象的方法:构造函数实例化(有参、无参构造器)、工厂模式实例化(静态,非静态工厂)即使用方法内部构造对象

无参构造组件(要求当前类必须包含无参构造函数):<bean id class=类全限定符 />,声明多个同类不同id组件默认单例模式,为两个组件对象

静态工厂创建组件:<bean id class=工厂类全限定符 factory-method=静态工厂方法 />

非静态工厂创建组件:<bean id=工厂对象 class=工厂类全限定符 /><bean id factory-bean=工厂对象(id)  factory-method=工厂方法 />

<bean id class=类全限定符 init-method = 该类初始化方法 destroy-method= 该类销毁方法/>容器会在对应时间结点调用方法

调用销毁方法需要使用close()

DI配置

基于构造函数的依赖注入或基于Setter的依赖注入

引用和被引用的组件必须全部在IoC容器中

IoC容器是高级容器,内部有缓存动作,会先创建所有对象再进行属性赋值(引用和被引用的类的代码顺序不重要)

通过单个构造参数注入:1.首先将引用和被引用的组件放在IoC容器中,有参构造器使用双标签<bean id class=类全限定符><constructor-arg value=属性值 ref=引用的beanid></bean>value和ref二选一

通过多个构造参数注入:在bean标签中写多个<constructor-arg value=属性值 ref=引用的beanid>,value赋值可以根据构造器参数顺序赋值根据构造参数名赋值,添加name属性,还可以通过参数下角标指定填写(参数顺序index,将参数列表当做从0开始的数组)

通过Setter方法注入:在bean标签中写多个<property name=属性名(调用setter方法的名,只是去掉了前面的set和第一个首字母小写) value=属性值 ref=引用的beanid>value和ref二选一

property标签实质寻找的是set方法

IoC容器创建

方法1:直接创建容器指定配置文件。ApplicationContext xxx = new 实现类(配置文件)

方法2:先创建空容器对象,再使用setConfigLocations()指定配置文件,再refresh刷新。(源码的配置过程)

IoC组件读取

方法1:通过beanId获取,getBean(beanid),返回值是Object对象,需要强转(不推荐)

方法2:通过beanId获取同时指定Class,getBean(beanId,class)

方法3:直接通过Class获取,getBean(class)。同一个类型在一个IoC容器中只能有一个组件

IoC配置一定是实现类,但是也可以通过接口获取值

只要instanceof ioc容器类型 == true就可以获取到

Bean标签

在IoC中bean标签对应的信息转成Spring内部BeanDefinition对象,在该对象内包含定义的信息

容器可以根据BeanDefinition对象反射创建多个bean对象,创建个数由作用域scope指定

scope=singleton为单例,bean对象始终为单实例,创建时机是容器初始化时,默认该选项

scope=prototype为多例,bean对象在容器中有多个实例,获取bean时创建

在WebApplicationContext环境下还有:

scope=request,请求范围内有效的实例

scope=session,会话范围有效的实例

factoryBean

factoryBean是一个标准化工厂,可以通过getObject方法进行组件实例化,要给创建的对象赋值需要在factoryBean中声明属性并赋给创建出的对象

组件实例化方式:构造函数<bean class类>、工厂模式<bean 工厂类 factory-method方法名>、factoryBean标准化工厂,通过getObject编写自己的实例化逻辑,<bean 工厂类>

getObject()返回工厂创建对象的实例并存入IoC容器

isSingleton()如果返回单例则为true,否则为false

getObjectType()返回getObject()方法返回的对象类型,不知道类型则返回null

使用场景:代理类的创建、第三方框架整合、复杂对象实例化

工厂也会被放入IoC容器,名字为@id

FactoryBean和BeanFactory区别

FactoryBean是Spring中一种特殊的组件,可以在getObject方法进行组件实例化,是一种能生产其他组件的组件。FactoryBean在容器启动时被创建,可以自定义任何所需的初始化逻辑,生产出定制化的bean

BeanFactory是Spring框架的基础,作为顶级接口定义了容器的基本行为,如管理bean生命周期,配置文件的加载和解析,bean的装配和依赖注入等。BeanFactory接口提供了访问bean的方式,如getBean方法获取指定的bean实例。它可以从不同来源获取bean定义,并将其转换为bean实例。同时BeanFactory还包含很多子类如ApplicationContext,提供了额外的强大功能

基于XML配置IoC

通过IoC配置:

1.bean标签中引入DruidDataSource类,并且赋属性url,driverClassName,username,password

2.bean标签中引入JdbcTemplate类,ref=上面创建的类id

还可以通过外部文件引入(只支持.properties文件),在beans中导入xmlns:context=文件路径,之后<context:property-placeholder location="classpath:文件名"(可以有多个class:文件名,用逗号隔开)>。在赋属性时可以直接使用文件中的类.属性名

通过IoC读取:1.通过实现类实例化创建IoC容器 2.通过getBean获取jdbcTemplate组件 3.进行数据库操作

update操作:

数据库操作中使用String类型编写sql语句

参数一:value中可以使用?代替值,但不能代替关键字和容器名;

参数二:Object传入占位符的值顺序从左开始;

返回值为int影响函数

select操作:

数据库操作中使用String类型编写sql语句

参数一:sql语句可以使用?

参数二:RowMapper列名和属性名的映射器接口

参数三:Object...pram可以变参数

返回值为rowMapper指定的对象

使用XML配置IoC缺点

1.注入的属性必须添加setter方法,代码结构乱;2.配置文件和java代码分离,编写不便;3.XML配置文件解析效率低

基于注解方式配置IoC

1.在类上添加IoC注解

2.告诉SpringIoC容器在哪些包下添加了IoC注解

注解

注解本质没有区别,只是用于后期区分

配置扫描包

扫描基本配置

指定了包中所有的类:<context:compoent-scan base-package="包名,包名..." />

排除包中某类注解:在context双标签中加<context:exclude-filter type="annotation" expression="包名">

指定包并指定注解:在context双标签中加<context:include-filter type="annotation" expression="包名">,需要在标签头中加use-default-filters="false"将包中注解全部排除

引入外部文件

<context:property-placeholder location="classpath:文件名"(可以有多个class:文件名,用逗号隔开)>

设置beanName

在注解后面加(value="name"),value=可以省略,直接写成("name")

默认name是类首字母小写加注解标签名

注解方式管理生命周期

周期方法命名为public void无参方法

@PostConstruct为注解指定初始化方法

@PreDestroy为注解指定销毁方法

单例模式不会管理销毁方法

注解方式控制作用域

@Scope(scopeName = COnfigurableBeanFactory.SCOPE_SINGLETON)单例作用域,其他作用域只需要修改最后部分即可

引用类型自动装配(DI)

@Autowired注解标识在成员变量、构造器、set方法上,首先在ioc容器中查找符合类型的组件对象,然后设置给当前属性DI

佛系装配

@Autowired中默认boolean required() default true,则组件必须存在,否则报错。佛系装配指修改为@Autowired(required=false),组件是否存在不影响

使用佛系装配会导致后续调用该组件返回空指针报错,一般不推荐使用

找到多个组件

第一种方法可以修改成员变量名为精确的要选择的组件id

第二种方法通过@Qualifier注解成员变量,设置value指定该成员变量装配组件

@Qualifier不能单独使用,必须配合@Autowired

@Resource注解

使用@Resource(name=“组件名”)相当于同时使用了@Qualifier(value=“组件名”)和@Autowired(required=true)

使用该注解需要导入包

对基本数据类型赋值

方法1:直接在声明变量时赋值

方法2:使用注解@value(“值”)赋值

使用value注解通常为了读取外部数据:

1.添加注解;2.扫描包;3.引入外部文件;4.将“值”写为"$(properties文件中变量名)"

第三方类配置

对于第三方只读文件仍需要使用xml进行配置

使用注解方式配置IoC缺点

1.自定义类可以使用注解方式,但第三方文件仍然使用XML方式配置

2.XML格式解析效率低

基于配置类方式配置IoC

完全注解开发:通过注解替代xml中的配置标签,完全取代xml配置

配置方法

第一步:配置类前加注解@Configuration,表示该类为配置类

第二步:配置包扫描:@ComponentScan(“包名”),value=可以省略

第三步:配置外部文件:@PropertySouce("classpath:文件名")

第四步:声明第三方依赖bean组件。

在配置类中声明方法,方法名为bean id;

方法返回值类型为bean组件的类型他的接口和父类;

方法体可以自定义实现过程,对每个property,设置private字符串,在前面用@value注解赋值,可以设置为配置类中全局变量或在方法形参列表中仅在方法中使用。通过set方法设置各种property。返回return创建好的对象。最后在配置类前加@bean注解即可。

beanName默认为方法名,可以用name或value属性设置beanname

指定周期方法:

方法一:使用原有注解PostConstruct+PreDestroy

方法二:使用@bean属性initMethod和destroyMethod指定

指定作用域:

@Scope(scopeName = COnfigurableBeanFactory.SCOPE_SINGLETON)

引用其他组件:

方法一:其他组件也是@bean方法,可以直接使用setbean名调用,参数中使用(方法())

方法二:将要调用的组件放入形参列表中,使用时直接调用。该方法调用要求必须有被调用组件在容器中,否则抛出错误。如果有多个同样组件需要形参名=beanId,注入多个使用逗号隔开

创建IoC容器:

ApplicationContext xxx = new AnnotationConfigApplicationContext(配置类)或者先创建空容器对象,再使用register()指定配置类,再refresh刷新。

@import注解

导入多个@Configuration,可以在其中一个前加@import(value=(其他标签)),导入这个@Configuration即可导入所有的

@SpringJUnitConfig注解

不用再主动创建IoC容器,需要的bean会在测试类中自动装配

@SpringJUnitConfig(locations = xml文件,value= 配置类)

可以直接@Autowired注入组件,直接使用

Spring AOP面向切面编程

AOP是对OOP的完善和补充,AOP将代码中重复的非核心业务提取到一个公共模块,最终再利用动态代理技术横向插入各个方法之中,解决非核心代码冗余问题

代理模式

在调用目标方法时不直接调用,而是借助代理类间接调用,为了让不属于目标方法核心逻辑的代码从中剥离解耦

静态代理

将被代理的目标对象声明为成员变量,附加功能由代理类中的代理方法来实现,通过目标对象来实现核心业务逻辑

代码需要提前编写,使用时局限性大,为了适应多种需求需要编写大量冗余代理类

动态代理

java原生代理

目标类必须有接口,接口生成一个代理类。返回的代理对象是目标类的兄弟,给接口创建另外的实现类,接值要用接口而不能用目标类接

生成代理对象需要传入类加载器,目标类接口和要执行的代理动作

调用代理的都会执行invoke方法,方法需要代理对象,目标方法(需要重写的方法)以及执行方法的参数args

Cglib动态代理

不要求目标类有接口,直接根据目标类生成一个子类对象,可以直接用原类接值

应用场景

日志记录(在不同时期发送日志),事务管理(开启和关闭事务冗余代码),安全控制(在执行每次操作前检查权限),性能监控(计算执行时间),异常处理,缓存控制,动态代理

术语名词

横切关注点:非核心代码,附加业务的添加位置

通知(增强):横切关注点中使用的实现方法。分为前置通知,返回通知(执行完成后),异常通知,后置通知(方法最终结束后),环绕通知(try catch finally)

连接点:可以被插入附加业务的位置

切入点:添加了附加业务的连接点

切面:切入点和业务的结合

目标:被代理的目标对象

代理:目标对象应用通知后创建的代理对象

织入:把通知应用到目标上,生成代理对象的过程,Spring在运行时织入

AOP实现

AOP作用对象必须在IoC容器中,创建完成代理对象,将代理对象也放入容器

首先正常写核心功能代码,之后将非核心代码插入

第一步:编写核心代码

第二步:编写非核心代码

有几个插入位置就写几个方法

第三步:使用注解分别用前置@before,后置@AfterReturning,异常@AfterThrowing,最后@After,环绕@Around注解标明方法

注解位置try{

前置

目标方法

后置

}catch(){

异常

}finally{

最后

}

第四步:配置切点表达式,选中插入的方法和切点@before("execution(包.类.方法(参数类型))")

第五步:用@Component加入容器,添加@Aspect注解配置切面

第六步:开启Aspect注解的支持,导入包

第七步:在配置类中添加非核心代码包的扫描

在xml配置文件中开启注解支持:<aop:aspectj-autoproxy />

在配置类中开启注解支持:@EnableAspectJAutoProxy

获取通知中的信息

1,获取通知中目标方法的信息,在目标方法中添加一个形参对象JoinPoint

获取类信息通过getTarget().getClass().getSimpleName()

获取方法名getSignature().getName()

获取方法的访问修饰符:首先获取int类型getSignature().getModifiers();然后使用Modifier.toString()方法转换为字符串形式

2,获取@AfterReturning中返回值,在目标方法中添加一个Object result对象形参,在注解value中添加returning=“result”

3,获取@Afterthrowing异常信息在目标方法中添加一个Throwable throwable对象形参,在注解value中添加throwing=“throwable”

切点表达式

 访问修饰符和返回值要么一起考虑,要么一起写作*

包的位置可以写出具体包路径,也可以用单层模糊service.*表示service下所有包,也可以用多层模糊com..impl,任意路径下的impl包,但是..不能开头,至少写成*..

类的名称可以写出具体类名,也可以用*模糊所有类,也可以部分模糊*impl表示以impl结尾的类

方法名语法和类一致

参数列表无参用(),有具体参数用(数据类型,数据类型,数据类型)不分顺序,模糊参数(..)有没有参数或有多个参数都可以,部分模糊(String..int)String开头,int结尾

重用切点表达式

方法1.在当前类中提取,定义一个空方法,添加注解@Pointcut(切点表达式方法),将切点方法的注解改为提取出来的方法名

方法2.创建一个存储切点的类,单独维护切点表达式,在切点位置注解中加类的全限定符.方法名

环绕通知

环绕通知创建一个单独的方法,需要再通知中定义目标方法的执行,在切点处直接写入实现方法

切面优先级

@Order(优先级值)值越小优先级越高

XML方式实现AOP

<aop:config>

声明切点标签

        <aop:pointcut id ="方法名" expression="execution(切点表达式)"/>

切面配置标签

        <aop:aspect ref="增强对象" order="优先级">

                <aop:before method="方法名" pointcut-ref="存储切点的类">

        </aop:aspect>

</aop:config>

bean标签获取

当IoC容器中有多个同类bean时,会抛出NoUniqueBeanDefinitionException异常

当bean对应的类实现了接口,并且接口只有这一个实现类,则通过接口类型和类获取bean获取到的是同一个对象

当接口有多个实现类,接口所有实现类都放入IoC容器中,根据接口类型获取会报NoUniqueBeanDefinitionException异常,根据类获取bean则正常

接口的实现类创建了切面类,并添加了通知,则通过接口类型获取bean正常,无法通过类获取bean。因为应用了切面后,在IoC容器中的是代理类的对象,而目标类没有被放入IoC容器中(jdk代理)

声明一个类,对其应用切面类并添加通知,则能通过类获取bean。因为cglib代理继承了该类

声明式事务Spring-tx

编程式事务指手动编写程序来管理事务。编程式事务灵活性高,但是编写大量事务控制代码容易出现问题,对代码可读性和可维护性有一定影响。细节未被屏蔽,代码复用性也不高

声明式事务指通过注解或XML配置的方式控制事务的提交和回滚

事务管理器

spring-tx包含声明式事务实现的基本规范

spring-jdbc包含DataSource方式事务管理器实现类DataSourceTransactionManager

spring-orm包含其他持久层框架的事务管理器实现类

最上方接口没有实质作用,中间提供了事务管理器方法,下方为具体类型的实现

事务实现

添加事务首先将事务放入IoC容器,再通过@Transactional注解开启事务

放入容器通过导入第三方配置类导入TransactionManager类,新建对象并将需要的连接池对象作为形参然后set注入,返回创建好的对象,再在配置类前面添加@EnableTransactionManager注解开启事务注解支持

在方法前加表示方法应用事务,在类前加表示类中所有方法都有事务

事务属性

只读

只有查询代码时推荐使用只读模式,可以提高查询事务的效率

@Transactional(readOnly=true)

一般在类前加只读,在类中的查询方法可以通过添加只读注解提高事务效率

超时时间

使超时的事务回滚,释放资源

@Transactional(timeout=秒数)

默认-1永不超时

如果方法和类上都有注解,方法的注解会覆盖类上的注解

事务异常

默认情况下发生运行时异常事务才会回滚,可以指定Exception异常控制所有异常回滚

@Transactional(rollbackFor=Exception.class,noRollbackFor=回退范围内某个异常不回滚)

事务隔离级别

@Transactional(isolation=隔离级别(字母全大写中间加下划线))

推荐设置读已提交

事务传播行为

方法之间互相调用行为

@Transactional(propagation)

=REQUIRED则父方法如果有事务,则加入事务,若没有事务则子方法单独创建一个事务。默认值,并且推荐使用该方法

==REQUIRES_NEW父方法无论有没有事务,字方法都新建独立事务

在同一个类中调用不会生效,因为Spring框架中使用代理模式实现事务机制,同类调用不使用代理,而是通过对象方法调用,注解设置不会被代理捕获,不会产生事务传播行为

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值