spring简介

spring几乎所有技术都基于springframework

一、spring的两大核心:IOC和DI

1.IOC控制反转

反转了资源的获取方向,以前要人为主动的new一个个对象,现在拥有了统一的IOC容器,进行管理,在需要时,只要提供接收资源对象的方式即可,不再需要创建对象了,也不再需要知道容器如何创建对象。

2.DI依赖注入

即Bean以一些提前设定好的方式,比如setter注入,构造器注入,接收来自于容器的资源,是对IOC的具体实现。

        2.1 setter注入

                在bean标签下,定义子标签<property>

                其中配置name为属性的名称,属性名称默认是setXxx方法去掉set后首字母小写。例如set方法setUid,对应的属性为uid,配置value为属性的值,都是字面量

                

        2.2 构造器注入

                通过有参构造为bean对象赋值;即在bean标签中定义子标签<constructor-arg>,配置name为参数名称(不是属性名),value配置值。

                注意:根据你设置的constructor的个数,他会自动匹配对应参数的构造方法,但若是含有多个相同个数参数的构造方法,那具体要通过哪个来赋值呢?

                解决方法是:在constructor标签中,定义name参数类型表明要赋值的属性

        2.3 特殊值注入

                2.3.1为字面量赋值,字面量就是没有引申意义,比如int a = 10;  10就是字面量,a是变量,代指10。但若是a加上单引号或双引号,那么也是字面量

                字面量赋值都是通过value属性来赋值的

                为非字面量赋值,例如赋值为null,需要再嵌套一层<null>标签,否则按照字面量赋值方法,赋值的结果只是字符串而已

                2.3.2当注入了一些特殊的字符,比如尖括号,因为尖括号是标签的结束和开始标记,需要进行转义,这里可以使用&lt;和&gt;代替小于号和大于号

                或者使用CDATA区,该区域内所有的字符都会原样解析,注意写的时候,不要写在属性的未知数,用一个value标签包裹起来,在idea中输入CD就出来了

                2.3.3 为类类型的属性赋值

        有三种方式:

引入外部bean:在property中定义ref属性指定引用的外部bean的id

使用内部bean:在property标签中再定义一个bean标签,里面定义类类型的属性

既然是内部bean,则作用域只存在包裹它的property中,也就是说ioc容器获取不到该内部bean

级联:通过对象名.属性名赋值,但是使用级联,必须先为对应的类类型进行实例化,其实级联就是对bean进行重新赋值

                2.3.4 为数组类型赋值

                在property中定义子标签<array>

        

                2.3.5 为list集合类型赋值

                和数组一样,使用内部bean方式,定义一个<list>子标签,里面若是字面量类型就用value,类类型就用ref

                如果外部有一个list类型的bean,也可以直接通过ref引入外部bean,需要引入一个新的util约束

                2.3.6 为Map集合类型赋值

                        通过子标签<map>实现,里面嵌套子标签<entry>定义key和value,类类型使用key-ref和value-ref

                使用util:map设置一个map集合类型,用法和util:list一样,在bean定义使用时用ref引用这个util的id就可以了

                2.3.7 使用p命名空间赋值(前提引入约束)

                

同样,类类型需要ref来赋值

        2.4 spring管理数据源和引入外部属性文件

2.4.1数据源本质上是一个对象,因此也可以上交给ioc容器管理

2.4.2 引入外部properties文件

然后在xml中通过<context:place-holder>来引入,引入后就可以使用${}的形式来替换value中写死的数据了

二、IOC容器在spring中的实现

1.BeanFactory,spring内部使用的接口,开发时不使用

2.ApplicationContext,BeanFactory的子接口,面向我们,一般常用这个接口

3.ConfigurableApplicationContext,是ApplicationContext的子接口,具有关闭,刷新容器的功能

4.实现类 

ClassPathXmlApplicationContext,通过类路径获取xml文件(常用)

FileSystemXmlApplicationContext,通过文件系统,读取磁盘上的xml文件

三、IOC容器创建对象的方式(反射+工厂模式)

        在resources目录下生成applicationContext.xml文件,在里面定义bean标签完成配置

1).获取bean的三种方式

通过类型获取bean,如果ioc容器中存在多个相同类型的bean,则获取时会报错

如果bean对应的类实现了接口,则通过接口类型也可以获取到bean,但前提是bean唯一

2). Bean的作用域

通过指定bean标签中的scope属性来定义作用域。

        singleton:默认,单例,通过单例获取的对象都是同一类型的对象

        prototype:在ioc容器中可以存在多例同类型的bean

不同的作用域,对bean的生命周期有不同影响。

        单例情况下,bean在ioc容器加载时就会自动创建,使用时自动返回当前bean即可。

        多例情况下,只有在自己主动获取bean对象时,ioc容器才会创建对应类型的bean,而且bean的销毁也不随ioc容器关闭而销毁了

        2.1 Bean的生命周期

因为bean对象不是我们创建,而是ioc容器自己创建,所以我们不需要知道实现过程,但需要指定对应的生命周期。

2.1.1. 实例化:通过无参构造器创建bean对象

2.2.2 依赖注入:给bean对象进行赋值操作 (setXxx方法注入或构造器注入)

2.3.3. 初始化前的方法:postProcessBeforeInitialization()

2.4.4. 初始化:在bean标签定义init-method为对应的方法引用

2.5.5. 初始化后的方法:postProcessAfterInitialization()

2.6.6. 销毁时的方法:在bean标签定义destory-method为对应的方法引用,在ioc容器关闭时,bean才会销毁。

        2.2 Bean的后置处理器,可以在bean的初始化之前或之后添加额外的操作

        创建方式:设置实现类实现BeanPostProcessor接口

                重写方法:

postProcessBeforeInitialization(),返回bean,并加入对应逻辑

postProcessAfterInitialization(),返回bean,并加入对应逻辑

        然后配置到ioc容器中,也就是在xml中定义bean标签,否则ioc无法识别。

3).FactoryBean

        是一个接口,需要创建实现类实现该接口,然后重写里面的两个方法

getObject():将一个bean对象交给ioc容器管理

getObjectType():设置bean工厂提供bean的类型

isSingleton():是否为单例

        然后把factoryBean的实现类在xml中配置为一个bean时,它就会把getObject中返回的对象作为一个bean交给ioc容器管理。

四、基于xml方式的bean自动装配

        上述配置bean方式都是在xml中手动装配,定义bean嵌套property,ref子标签。

在mvc的三层架构中,controller依赖于service,service依赖于dao,所以在基于xml手动装配中,要在对应依赖的类中添加get,set方法完成依赖注入,然后在xml文件里配置mvc的三层bean结构,bean里添加property完成依赖关系

而自动装配是按照指定的策略,在ioc容器中匹配到某个bean,自动为类类型或接口类型的bean赋值。

在xml方式,可以在bean标签的属性定义autowire属性,来代替property的手动装配,autowire的属性有多种:

byType:按类型自动装配

byName:按根据属性的属性名作为bean的id来进行自动装配

no:不装配

dafault:默认值,和no一样,不自动装配

若在ioc容器中,根据类型匹配bean,一个bean都匹配不到,此时不再匹配,使用默认值null进行赋值,这时就容易发生空指针异常,而且同时有且只有一个相同类型的bean

五、基于注解的方式管理bean

        1.基于注解实现ioc

        在MVC的三层架构中,使用注解@Controller,@Service,@Repository,@Component

来分别将类交给ioc容器。就不用再在xml里定义bean标签了

        2.配置完注解,需要让ioc容器扫描到,所以要在xml中定义组件扫描

 

base-package定义了扫描的包名

子标签exclude-filter定义了不扫描哪些包,type属性有annotation通过注解扫描和assignable通过类扫描, expression是注解或类的全类名

子标签include-filter定义了只扫描哪些包,使用前需要先设置属性user-default-filters为false,表示不扫描所有包,这样才能只扫描某些包

通过注解扫描配置的bean,默认id为属性的首字母小写,也可以通过注解里的value属性自定义bean的id

        3.基于注解完成自动装配

使用@Autowired代替xml中的autowired属性,并且不用再添加get,set方法完成注入

@Autowired可以放在成员变量上或set方法上。

@Autowired默认是按类型匹配也就是byType,如果ioc容器中有多个同类型的bean,则会自动

转换为按名称byName的方式进行装配,如果这两种方式都无法实现自动装配

可以再添加一个@Qualifer注解,通过value属性指定要装配的bean的id,来进行装配

使用注解自动装配,时要求必须完成装配,如果无法装配成功,就会报错,可以设置required属性为false,表示不强制进行自动装配,即装配不上时,使用默认值。

六、AOP

AOP是面向切面编程,指的是在不修改源代码的情况下,对程序进行功能增强的一种技术

        1. AOP的相关术语

        横切关注点:从目标对象抽取出来的非核心业务代码。可以存在多个

        通知:每一个横切关注点上,都需要对应的通知方法来实现,就叫做通知方法

        1)前置通知@Before:在代理的目标方法执行前执行

        2)返回通知@AfterReturning:在代理的目标方法成功结束后执行

        3)异常通知@AfterThrowing:在代理的目标方法异常结束后执行

        4)后置通知@After:在代理的目标方法最终finally结束后执行

        5)环绕通知@Around:使用try catch finally包裹的方法,其实是上述四种方法的集合

        切面:封装通知方法的类Aspect

        目标:被代理的目标对象

        代理:向目标对象应用代理后生成的代理对象,自动创建

        连接点:逻辑概念,就是抽取横切关注点的位置

        切入点:物理概念,定位连接点,然后套入增强的方法

        2. 基于注解的AOP实现

        1)通过AspectJ和代理方式实现,在pom文件引入对应依赖spring-aspects

        2)  定义切面类Aspect,并使用@Component、@Aspect注解交给ioc容器管理,并声明为切面类,并且在配置文件定义组件扫描<context:component-scan>,定义<aop:aspectj-autoproxy>表示开启基于注解的aop

        3)在切面类定义通知方法,每一种通知方法对应了不同的注解,在注解中,必须指定切入点表达式,表明套入源代码的地方,即横切关注点,切入点表达式为

execution():里面指定访问修饰符,返回值类型,包,方法,参数,其中前两个一般都会省略。

该图是使用了切入点表达式的重用,通过@Pointcut定义一个方法,定义一个公有的切入点表达式

之后所有的通知方法都可以使用该表达式

                

        4)定义了aop,就不能直接访问目标对象了,必须通过代理对象执行目标对象的方法,因为是动态代理,不知道具体代理对象的类型,但知道,代理对象一定实现了和目标对象一样的接口或父类,所以获取父类接口,然后再执行方法即可。

        5)在通知方法中获取连接点的信息

                可以在通知方法的参数列表中,定义形参JoinPoint jp

                该类型的参数,包含了连接点的信息,通过对应方法就可以获得连接点的方法签名,参数等等

                注意,在环绕通知中,只能定义ProceedingJoinPoint对象,功能和JoinPoint一样,但多了一个proceed()方法,表示调用目标对象方法

        6)切面的优先级,因为我们可能会创建多个切面,多个切面间,通知方法的执行顺序就不知道了,这样可以使用@Order注解,里面的value属性定义一个int类型的数字,数字越小,默认优先级越高,也就会优先执行该切面类的通知方法

        7)基于xml的aop实现

如图配置即可,首先关闭基于注解的aop标签,然后定义<aop:config>

开启手动配置aop,定义子标签<aop:aspect>表明切面类 ref是切面类的全限定类名

        <aop:aspect>中嵌套子标签来定义通知方法或者重用的切入点表达式

七、spring整合junit完成声明式事务

        在pom文件引入依赖spring-test,这样在test中,就不用再主动获取ioc容器了,转而通过注解

@RunWith表示使用junit4的测试环境

@ContextConfiguration表示读取的xml配置文件

        以往的事务都是编程式事务,也就是事务相关的操作全部由自己完成,代码重用性不高

        通过声明式事务,可以把相同逻辑的代码抽取到切面并封装1,我们只需要在配置文件简单配置即可操作,提高了效率,消除了冗余的代码

        1. 基于注解的声明式事务

        pom中引入对应依赖,在配置文件中配置数据源连接到数据库

        在配置文件中配置事务管理器

        开启事务的注解驱动

        这样就能在业务类中或对应的方法上,定义注解@Transactional,表示开启为当前整个类或方法开启事务

        在注解@Transactional中包含了多个属性

                1)只读readonly,这个属性只涉及读操作,对增删改设置只读会爆出sql异常

                2)超时timeout,超过一定时间未执行成功的操作,会自动放弃并报超时异常

                3)回滚rollback,遇到什么异常时会进行回滚,有四个属性

rollbackFor:因为什么异常的class对象来回滚

rollbackForClassName:因为一个字符串的异常类型的全限定类型名来回滚

norollbackFor:不因为什么异常的class对象来回滚

norollbackForClassName:不因为一个异常类型的全限定类型名来回滚

声明式事务默认情况是对所有的运行时异常都进行回滚,所以很少设置rollbackFor和rollbackForClassName

                4)事务的隔离级别

                5)事务的传播行为

                定义属性propagation。

                当a事务中调用b时,因为a,b都有各自的事务,那么b究竟按照谁的事务,是a的,还是b本身的事务进行操作?

Propagation.REQUIRED是默认值,意思是使用调用者a的事务

Propagation.REQUIRES_NEW意思是调用事务b时,不使用事务a,反而开启一个新的事务,也就是使用事务b

        2. 基于xml的声明式事务

  配置事务通知

        

  

              

  • 23
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值