Spring

1.Spring的核心

控制反转(IoC)和面向切面(AOP)

2.IOC

也叫做:控制反转:

  1. Inversion Of Control 简称IOC
  2. IOC 就表示控制反转
  3. 控制反转: 把对象的创建交给外部的容器,程序中只需要接收获取对象即可,不需要关注对象由谁创建创建的细节。
  4. 控制反转,不是spring所特有的,是一个通用的概念。只是Spring提供了IOC控制反转容器。

3.SpringIOC容器(理解)

IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法。

Spring的IOC有三种注入方式 :构造器注入、setter方法注入、接口注入。

1.SpringIOC容器,创建容器几种方式

由以下三种方式

|-- ClassPathXmlApplicationContext 加载类路径下的配置文件

|-- FileSystemXmlApplicationContext 加载外部的配置文件

|-- AnnotationConfigApplicationContext 加载注解类的方式创建容器

PS:

|-- BeanFactroy SpringIOC容器的顶层接口. 创建容器默认不创建单例的对象,默认采用延迟加载创建对象的机制。

|-- ApplicationContext 子接口。 默认创建容器时候就创建单例的对象。

面试题

BeanFactory和ApplicationContext有什么区别?

    BeanFactory和ApplicationContext是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。

(1)BeanFactory:是Spring里面最顶层的接口,包含了各种Bean的定义,读取bean配置文档,管理bean的加载、实例化,控制bean的生命周期,维护bean之间的依赖关系。ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:

①继承MessageSource,因此支持国际化。

②统一的资源文件访问方式。

③提供在监听器中注册bean的事件。

④同时加载多个配置文件。

⑤载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层。

(2)①BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,我们就不能发现一些存在的Spring的配置问题。如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

    ②ApplicationContext,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入所有的单实例Bean,通过预载入单实例bean ,确保当你需要的时候,你就不用等待,因为它们已经创建好了。

    ③相对于基本的BeanFactory,ApplicationContext 唯一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

(3)BeanFactory通常以编程的方式被创建,ApplicationContext还能以声明的方式创建,如使用ContextLoader。

(4)BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。

4.Spring创建对象的三种方式

方式1:默认无参数构造函数创建对象(常用)

PS:其实还有有参数构造函数创建,但一般只有在依赖注入构造器参数时才创建,在bean里面子标签写constructor-arg标签:通过有参数构造器创建对象;

方式2:工厂类的静态方法创建对象

方式3:工厂类的实例方法创建对象

1.默认无参数构造函数创建对象

直接在bean.xml配置

在这里插入图片描述

配置细节

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        1. 创建对象,入门程序
           User user = new User();
           User user2 = user;
        2. 创建对象的细节
           bean     表示一个需要创建的对象。不能为接口(通常这里都需要我们newclass  要创建对象的类型全名
             id     表示对象的名称; 一次只能定义一个对象;
             name   表示对象的名称; 一次可以定义多个对象,用逗号或空格隔开
                    小结:
                        2.1 推荐使用id。
                        2.2 默认创建的是单例的对象
                        2.3 在创建容器时候,默认就创建单例的对象。
             scope   指定对象的范围(单例、多例)
                     singleton 默认值,表示单例. 创建IOC容器,默认创建单例的对象。
                     prototype 多例,每次从容器中获取对象,都会创建一个新的对象
                               创建容器默认不创建多例的对象,总是在用到时候才创建。
                     request:web项目中,将对象存入request域中【了解】
                     session:web项目中,将对象存入session域中【了解】
                     globalsession:web项目中,应用在集群环境,
             lazy-init="true"
                初始化IOC容器不会去创建懒加载的对象 而是使用对象是才创建 默认值是false                           
                     1.只对单例对象有效;
                     2. 对单例的对象,配置延迟初始化,表示在第一次使用时候才创建。
                     3. 小结
                        dao、service: 默认即可,就是单例,且在创建ioc容器时候就创建单例的对象。
                        
              init-method="init"
                            对应User对象的init()方法,在创建对象之后始终执行
              destroy-method="preDestroy"
                            对应User对象的preDestroy()方法,在销毁容器之前执行。
                            销毁容器:调用容器的close()方法。
                            注意:只对单例有效。
    -->
    <bean
            id="user"
            name="user2,user3 user4"
            class="com.itheima.entity.User"
            scope="prototype"
            lazy-init="true"
            init-method="init"
            destroy-method="preDestroy"
    />
</beans>

2.工厂类的静态方法创建对象

在这里插入图片描述

在bean里面添加factory-method就可以调用静态方法了,

调用某个类的静态方法创建对象,使用: class + factory-method

在这里插入图片描述

3.工厂类的实例方法创建对象

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

5.依赖注入的方式

方式一:带参数构造函数

方式二:set方法【最常用】

方式三:p名称空间

概念

依赖注入,DI,Dependency Injection , 就是IOC容器提供的另外一块功能:给对象属性赋值

1.带参数构造函数

在这里插入图片描述

在这里插入图片描述

2.set方法

在这里插入图片描述

在这里插入图片描述

3.p名称空间

在这里插入图片描述

6.注解实现创建对象(注解实现要在xml配置扫描注解)

基于注解的 IOC 配置,用于创建对象的注解

创建对象的注解有下面四个:

@Component: 创建对象,加入ioc容器。举例:工具类

@Controller: 同@Component 一般用于表现层的注解。
@Service: 同@Component 一般用于业务层的注解。
@Repository: 同@Component 一般用于持久层的注解。

7.注解实现注入数据(依赖注入)(注解实现要在xml配置扫描注解)

基于注解的 IOC 配置,注入数据 A @Autowired修饰字段

@Autowired注解说明

ioc容器中,给对象的属性注入数据时用@Autowired注解

  1. @Autowired注入数据,可以根据名称或类型注入。
  2. @Autowired注解,可以定义在字段上,也可以定义在方法上。

1.定义在字段上,根据名称或类型注入

在这里插入图片描述

在这里插入图片描述

2.定义在方法上,根据名称或类型注入

在这里插入图片描述

在这里插入图片描述

PS:

在这里插入图片描述

dao接口已经用注解形式创建对象了,所以不用在bean里面配置。

8.其他注解

1.@Value:

可以直接给简单类型的字段赋值。

可以获取配置文件值。(纯注解讲解)

在这里插入图片描述

PS:@Value获取配置文件,但前提是

使用@PropertySource 加载类路径下的配置文件

在这里插入图片描述

2.@Resource

相当于@Autowired注解,也可以根据名称或类型注入。也可以指定名称或类型注入。

简单来说 @Resource = @Autowired + @Qualifier,但在jdk1.8以后版本,不提供此注解支持

3.@Qualifier

@Autowired是根据指定的名称,但不能去容器中查找对应的对象注入,这时需要用到@Qualifier

在这里插入图片描述

4.对象范围与生命周期相关注解

​ 1.@Scope

​ @PostConstruct

​ @PreDestroy

​ @Lazy

/**
 * @Scope("singleton")
 * 指定对象为单例或多例。
 
 * @Lazy
 * 延迟创建单例的对象
 
 * @PostConstruct
 * 此注解修饰的方法,会在创建对象之后执行。始终执行。
 
 * @PreDestroy
 * 此注解修饰的方法,会在调用容器的close()方法,销毁容器时候执行。只对单例有效。
 */

xml方式

<bean id=""  class="" 
      scope=""                使用@Scope注解取代
      init-method=""          使用@PostConstruct注解取代
      destroy-method=""       使用@PreDestroy注解取代
      lazy-init=""            使用@Lazy注解取代
/>

9.Spring的AOP理解:

AOP主要用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于日志、事务等处理。

AOP实现的关键在于 代理模式,AOP代理主要分为静态代理和动态代理。

静态代理的代表为AspectJ;

动态代理则以Spring AOP为代表。

(1)AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)植入到Java字节码中,运行的时候就是增强之后的AOP对象。

(2)Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是每次运行时在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:

①JDK动态代理只提供接口的代理,不支持类的代理。核心InvocationHandler接口和Proxy类,InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy利用 InvocationHandler动态创建一个符合某一接口的的实例, 生成目标类的代理对象。

②如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

(3)静态代理与动态代理区别在于生成AOP代理对象的时机不同,相对来说AspectJ的静态代理方式具有更好的性能,但是AspectJ需要特定的编译器进行处理,而Spring AOP则无需特定的编译器处理。

InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最终生成的代理实例; method 是被代理目标实例的某个具体方法; args 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。

10.SpringAOP

1.AOP

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

什么是切面?切面就是重复执行的代码形成的类,叫做工具类,也叫做切面类。

什么是面向切面编程?面向重复的代码编程,重复的代码只要写一次,不需要自己调用,自动调用自动运行。统一维护。

举例:面向切面编程,有哪些切面类?

1. 日志切面类
2. 事务的切面类
3. 权限切面

面向切面编程好处?

重复的代码只要写一次,不需要自己调用,自动调用自动运行。

解耦。举例: 日志记录代码与业务代码解耦。事务控制代码与业务代码解耦。

2.SpringAop怎样做日志?

有两种方式,注解方式和xml方式

实现方式为

  • 1.做一个日志切面类

    <!--2. 创建切面类-->
        <bean id="logAspect" class="com.itheima.utils.LogAspect"/>
    
  • 2.做一个切入点

    <!--3. Aop配置-->
        <aop:config>
            <!--3.0 配置切入点表达式(AspectJ表达式)-->
            <aop:pointcut id="pt" expression="execution(* com.itheima.service.impl.UserServiceImpl.*())"/>
            <!--3.1 配置切面-->
            <!--ref 指定引用的切面类-->
            <aop:aspect ref="logAspect">
                <aop:after method="insertLog" pointcut-ref="pt"/>
            </aop:aspect>
        </aop:config>
    
  • 3.把日志植入到目标对象中

    <aop:aspect ref="logAspect">
                <aop:after method="insertLog" pointcut-ref="pt"/>
            </aop:aspect>
    

  • aop的通知类型:

可以在记录日志的切面类进行通知

【前置通知】 在执行目标对象方法之前执行

【后置通知】 在执行目标对象方法之后执行, 出现异常不执行。

【异常通知】 在执行目标对象方法出现异常时候才执行

【最终通知】 在执行目标对象方法之后执行,始终执行

【环绕通知】 环绕目标方法执行(相当于前面四种通知的结合体)

在xml配置或者注解实现

~~~xml
 <!--3. Aop配置-->
    <aop:config>
        <!--3.0 配置切入点表达式-->
        <aop:pointcut id="pt" expression="bean(*Service)"/>
        <!--3.1 配置切面-->
        <aop:aspect ref="logAspect">
            <!--注意:后置通知,一定要放到最终通知的前面。执行结果与配置顺序有关系。-->
            <aop:before method="before" pointcut-ref="pt"/>
            <aop:after-returning method="afterReturning" pointcut-ref="pt"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>
            <aop:after method="after" pointcut-ref="pt"/>
        </aop:aspect>
    </aop:config>
~~~

11.Spring事务

spring事务包括声明式事务和编程式事务

12.事务的传播行为 (PROPAGATION),

作用: 控制事务的边界。 说白了,就是通过传播行为指定如何管理事务。

REQUIRED(required)

  1. 默认值。如果一个方法指定事务的传播行为是REQUIRED,就表示当前运行方法必须有事务环境,如果当前方法没有事务,就创建一个新的事务。如果当前执行的方法有事务环境,就把当前方法加入当前事务环境中。“智能 人性化 合理”
  2. 应用: 增删改

SUPPORTS(supports)

  1. 如果一个方法指定事务的传播行为是SUPPORTS, 表示当前方法支持事务环境的运行。对事务的要求是:可有可无。
  2. 应用:查询

REQUIRES_NEW(requires_new)

  1. 不管当前运行方法是否有事务环境,都会创建一个全新的事务。
  2. 应用:

在这里插入图片描述

13.怎样做spring声明式事务

可以通过xml方式或者注解方式实现

实现:

1.配置事务管理器

xml方式

<!--5. Spring声明式事务控制的配置-->
    <!--5.1 配置事务管理器,也叫做事务切面类。Spring已经提供了针对连接池的事务控制的实现。-->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

2.配置事务通知规则

xml方式

<!--5.2 配置事务通知规则。作用:拦截到方法后,如何管理事务,在这里配置。-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--find/get等开头的方法,事务可有可无,只能进行查询操作。-->
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
            <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
            <tx:method name="search*" propagation="SUPPORTS" read-only="true"/>
            <tx:method name="query*" propagation="SUPPORTS" read-only="true"/>
            <tx:method name="load*" propagation="SUPPORTS" read-only="true"/>
            <!--其他所有方法,必须有事务环境,支持读写操作。-->
            <tx:method name="*" propagation="REQUIRED" read-only="false"/>
        </tx:attributes>
    </tx:advice>

3.Aop配置(Aop配置 = 切入点表达式 + 事务通知规则)

xml方式

 <!--5.3 Aop 配置-->
    <aop:config>
        <!--5.3.1 配置切入点表达式-->
        <aop:pointcut id="pt" expression="execution(* com..*ServiceImpl.*(..))"/>
        <!--5.3.2 建立切入点表达式与通知规则的对应关系-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
    </aop:config>

注解形式

在bean.xml配置

<!--5. Spring声明式事务控制的配置-->
    <!--5.1 配置事务管理器,也叫做事务切面类。Spring已经提供了针对连接池的事务控制的实现。-->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

事务注解支持


<tx:annotation-driven transaction-manager="transactionManager"/>

就可以使用注解:@Transactional  

类上,方法上使用@Transactional

/**
 * @Transactional
 * 1. Spring声明式事务的注解支持。
 * 2. 可用范围
 *      定义在类上:表示当前类的所有方法都应用事务。 最常用。
 *      定义在类的方法上: 表示当前方法应用事务。
 *      定义在接口或父类上,表示所有实现了接口或继承父类的子类的所有方法都应用事务。
 *      定义在接口方法或父类方法上,表示所有重写了该方法的地方都就应用事务。
 * 3. 事务属性
 *      propagation
 *          REQUIRED 默认值,表示必须有事务环境.
 *      isolation
 *          DEFAULT  使用数据库默认的隔离级别
 *      timeout
 *          -1       默认值,表示不指定事务的超时时间。由数据库底层决定事务超时时间。
 *      readOnly
 *          false    默认值,支持读写操作
 *
 *      noRollbackFor 指定遇到指定的异常不回滚。
 *
 */
@Service
@Transactional(
        propagation = Propagation.REQUIRED,
        isolation = Isolation.DEFAULT,
        timeout = -1,
        readOnly = false,
        noRollbackFor = {ArithmeticException.class,NullPointerException.class}
)
public class{}

Spring声明式事务原理:

​ 原理:Aop

​ Aop原理: 动态代理

​ 动态代理: 方法

Spring声明式事务的优缺点:

​ 优点:

​ 1. 解耦: 事务代码与业务代码完全解耦。

​ 2. 每一个项目都要连接数据库,那就必须由事务控制,spring已经提供了。

​ 我们只需要写业务,不需要关注事务。

​ 缺点:

​ Spring声明式事务,是粗粒度的事务控制。

​ 是方法级别的事务控制,只能对方法进行事务控制。

​ 不能对方法的某几行进行事务控制。

​ 细粒度的事务控制:

​ 可以对方法任意行进行事务控制。

​ 细粒度的事务控制,只能硬编码的方式、自己写事务控制代码完成。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值