什么是Spring
  • Spring是一个轻量级的IoC和AOP容器框架。是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用程序的开发,它使得开发者只需要关心业务需求。常见的配置方式有三种:基于XML的配置、基于注解的配置、基于Java的配置。
    主要由以下几个模块组成:
  1. Spring Core:核心类库,提供IOC服务;
  2. Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
  3. Spring AOP:AOP服务;
  4. Spring DAO:对JDBC的抽象,简化了数据访问异常的处理;
  5. Spring ORM:对现有的ORM框架的支持;
  6. Spring Web:提供了基本的面向Web的综合特性,例如多方文件上传;
  7. Spring MVC:提供面向Web应用的Model-View-Controller实现。
  • 基于XML的配置
    在 Spring 框架中,依赖和服务需要在专门的配置文件来实现,常用的 XML 格式的配置文件。这些配置文件的格式通常用开头,然后一系列的 bean 定义和专门的应用配置选项组成。
    SpringXML 配置的主要目的是使所有的 Spring 组件都可以用 xml 文件的形式来进行配置。这意味着不会出现其他的 Spring 配置类型(比如声明的方式或基于 Java Class 的配置方式)
    Spring的XML配置方式是使用被Spring命名空间的所支持的一系列的XML标签来实现的。Spring 有以下主要的命名空间:context、beans、jdbc、tx、aop、mvc 和 aso
<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-3.0.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"></bean>
</beans>
  • 基于Java的配置
    Spring 对 Java 配置的支持是由@Configuration 注解和@Bean 注解来实现的。由@Bean 注解的方法将会实例化、配置和初始化一个新对象,这个对象将由 Spring 的 IoC 容器来管理。@Bean 声明所起到的作用与 元素类似。被 @Configuration 所注解的类则表示这个类的主要目的是作为 bean 定义的资源。被@Configuration 声明的类可以通过在同一个类的内部调用@bean 方法来设置嵌入 bean 的依赖关系。
@Configuration
public class BeanConfig {
    @Bean
    public UserDao userDao(){
        return new UserDao();
    }
}
  • 基于注解的配置
    Spring 在 2.5 版本以后开始支持用注解的方式来配置依赖注入。可以用注解的方式来替代 XML 方 式的 bean 描述,可以将 bean 描述转移到组件类的内部,只需要在相关类上、方法上或者字段声明上使用注解即可。注解注入将会被容器在 XML 注入之前被处理,所以后者会覆盖掉前者对于同一个属性的处理结果。
@Component("userDao")
public class UserDao {
    
}
Spring的IOC和AOP机制
  • 主要用到的设计模式有工厂模式和代理模式。
    IOC就是典型的工厂模式,通过sessionfactory去注入实例。
    AOP就是典型的代理模式的体现。
  • IOC:控制反转也叫依赖注入(DI),利用了工厂模式将对象交给容器管理,你只需要在spring配置文件中配置相应的bean,以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的时候,就把它已经初始化好的那些bean分配给你需要调用这些bean的类(假设这个类名是A),分配的方法就是调用A的setter方法来注入,而不需要你在A里面new这些bean了。
  • spring mvc 设置超时时间 spring mvc dao_动态代理

  • AOP:面向切面编程。(Aspect-Oriented Programming)
    AOP可以说是对OOP的补充和完善。OOP引入抽象、封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。将程序中的交叉业务逻辑(比如安全,日志,事务等),封装成一个切面,然后注入到目标对象(具体业务逻辑)中去。
    实现AOP的技术,主要分为两大类:
    一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;
    二是采用静态织入的方式,引入特定的语法创建“切面”,从而使得编译器可以在编译期间织入有关“切面”的代码。
Spring的IOC理解
  • (1)IOC就是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由自己把控的,而现在这种权力转移到Spring容器中,并由容器根据配置文件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复用。DI依赖注入,和控制反转是同一个概念的不同角度的描述,即应用程序在运行时依赖IoC容器来动态注入对象需要的外部资源。
  • (2)最直观的表达就是,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法。
  • (3)Spring的IOC有三种注入方式 :构造器注入、setter方法注入、根据注解注入。
Spring的AOP理解
  • AOP 是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。简单来说就是统一处理某一“切面”(类)的问题的编程思想,比如统一处理日志、异常等。
    OOP面向对象,允许开发者定义纵向的关系,但并不适用于定义横向的关系,导致了大量代码的重复,不利于各个模块的重用。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则无需特定的编译器处理。
  • ArrayList的代理类
Spring中Autowired和Resource关键字的区别
  • @Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。
    1、共同点
    两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。
    2、不同点
    (1)@Autowired
    @Autowired为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入。
public class TestServiceImpl {
    
    // 下面两种@Autowired只要使用一种即可
    @Autowired
    private UserDao userDao; // 用于字段上
   
    @Autowired
    public void setUserDao(UserDao userDao) { // 用于属性的方法上
        this.userDao = userDao;
    }

}
  • @Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。如下:
public class TestServiceImpl {
    
    @Autowired
    @Qualifier("userDao")
    private UserDao userDao;

}
  • (2)@Resource
    @Resource默认按照byName自动注入,由J2EE提供,需要导入包javax.annotation.Resource。
    @Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
public class TestServiceImpl {

    // 下面两种@Resource只要使用一种即可
    @Resource(name="userDao")
    private UserDao userDao; // 用于字段上
    
    @Resource(name="userDao")
    public void setUserDao(UserDao userDao) { // 用于属性的setter方法上
        this.userDao = userDao;
    }

}
  • @Resource装配顺序:
    ①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
    ②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
    ③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
    ④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
  • @Resource的作用相当于@Autowired,只不过@Autowired按照byType自动注入。
依赖注入的方式有几种
  • 构造器注入:
    将被依赖对象通过构造函数的参数注入给依赖对象,并且在初始化对象的时候注入。
    优点:对象初始化完成后便可获得可使用的对象。
    缺点:当需要注入的对象很多时,构造器参数列表将会很长;不够灵活。若有多种注入方式,每种方式只需注入指定几个依赖,那么就需要提供多个重载的构造函数,麻烦。
  • setter方法注入
    IoC Service Provider通过调用成员变量提供的setter函数将被依赖对象注入给依赖类。 如果通过set方法注入属性,那么spring会通过默认的空参构造方法来实例化对象,所以如果在类中写了一个带有参数的构造方法,一定要把空参数的构造方法写上,否则spring没有办法实例化对象,导致报错。
    优点:灵活。可以选择性地注入需要的对象。
    缺点:依赖对象初始化完成后由于尚未注入被依赖对象,因此还不能使用。
  • 接口注入
    依赖类必须要实现指定的接口,然后实现该接口中的一个函数,该函数就是用于依赖注入。该函数的参数就是要注入的对象。
    优点:接口注入中,接口的名字、函数的名字都不重要,只要保证函数的参数是要注入的对象类型即可。
    缺点:侵入行太强,不建议使用
解释Spring支持的几种bean的作用域
  • Spring容器中的bean可以分为5个范围:
  • (1)singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。
    这种 bean 范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有一个 bean 的实例,单例的模式由 bean factory 自身来维护。
  • (2)prototype:为每一个bean请求提供一个实例。
  • (3)request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
  • (4)session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
  • (5)global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。
    Spring 框架提供了以下四种方式来管理 bean 的生命周期事件:
    InitializingBean 和 DisposableBean 回调接口
    针对特殊行为的其他 Aware 接口
    Bean 配置文件中的 init()方法和 destroy()方法
    @PostConstruct 和@PreDestroy 注解方式
spring bean的生命周期
  • 首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy。
    Spring上下文中的Bean生命周期也类似,如下:
  • (1)实例化Bean:
    对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
  • (2)设置对象属性(依赖注入):
    实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息以及通过BeanWrapper提供的设置属性的接口完成依赖注入。
  • (3)处理Aware接口:
    接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
    ①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;
    ②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
    ③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
  • (4)BeanPostProcessor:
    如果想对Bean进行一些自定义的处理,那么可以让Bean实现BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
  • (5)InitializingBean 与 init-method:
    如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
  • (6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
  • 以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
  • (7)DisposableBean:
    当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
  • (8)destroy-method:
    最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
Spring 框架中的单例 Beans 是线程安全的么
  • Spring 框架并没有对单例 bean 进行任何多线程的封装处理。关于单例 bean 的线程安全和并发问题需要开发者自行去搞定。但实际上,大部分的 Spring bean 并没有可变的状态(比如 Serview 类 和 DAO 类),所以在某种程度上说 Spring 的单例 bean 是线程安全的。如果你的 bean 有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。 最浅显的解决办法就是将多态 bean 的作用域由“singleton”变更为“prototype”。
请举例说明如何在 Spring 中注入一个 Java Collection
  • Spring 提供了以下四种集合类的配置元素:
    <list> : 该标签用来装配可重复的 list 值。
    <set> : 该标签用来装配没有重复的 set 值。
    <map>: 该标签可用来注入键和值可以为任何类型的键值对。
    <props> : 该标签支持注入键和值都是字符串类型的键值对.。
<beans>        
    <!-- Definition for javaCollection -->        
    <bean id="javaCollection" class="com.howtodoinjava.JavaCollection">           
        <!-- java.util.List -->           
        <property name="customList">                                            
            <list>                
                <value>INDIA</value>                
                <value>Pakistan</value>                
                <value>USA</value>                
                <value>UK</value>             
            </list>           
        </property>                

        <!-- java.util.Set -->          
        <property name="customSet">             
            <set>                 
                <value>INDIA</value>                 
                <value>Pakistan</value>                 
                <value>USA</value>                 
                <value>UK</value>             
            </set>           
        </property>                
        
        <!-- java.util.Map -->          
        <property name="customMap">             
            <map>                
                <entry key="1" value="INDIA"/>                
                <entry key="2" value="Pakistan"/>                
                <entry key="3" value="USA"/>                
                <entry key="4" value="UK"/>             
            </map>           
        </property>     

        <!-- java.util.Properties -->         
        <property name="customProperies">             
            <props>                 
                <prop key="admin">admin@nospam.com</prop>                 
                <prop key="support">support@nospam.com</prop>             
            </props>         
        </property>              
    </bean>     
</beans>
在 Spring 框架中共有 5 种自动装配:
  1. no:这是 Spring 框架的默认设置,在该设置下自动装配是关闭的,开发者需要自行在 bean 定义中用标签明确的设置依赖关系。
  2. byName:该选项可以根据 bean 名称设置依赖关系。当向一个 bean 中自动装配一个属性时,容器将根据 bean 的名称自动在配置文件中查询一个匹配的 bean。如果找到的话,就装配这个属性, 如果没找到的话就报错。
  3. byType:该选项可以根据 bean 类型设置依赖关系。当向一个 bean 中自动装配一个属性时,容器将根据 bean 的类型自动在在配置文件中查询一个匹配的 bean。如果找到的话,就装配这个属性, 如果没找到的话就报错。
  4. constructor:构造器的自动装配和 byType 模式类似,但是仅仅适用于与有构造器相同参数的 bean, 如果在容器中没有找到与构造器参数类型一致的 bean,那么将会抛出异常。
  5. autodetect:该模式自动探测使用构造器自动装配或者 byType 自动装配。首先会尝试找合适的带参数的构造器,如果找到的话就是用构造器自动装配,如果在 bean 内部没有找到相应的构造器或者是无参构造器,容器就会自动选择 byType 的自动装配方式。
如何开启基于注解的自动装配
  • 要使用 @Autowired,需要注册 AutowiredAnnotationBeanPostProcessor,可以有以下两种方式来实现:
    1、引入配置文件中的下引入 <context:annotation-config>
<beans>     
    <context:annotation-config />    
</beans>

2、在 bean 配置文件中直接引入 AutowiredAnnotationBeanPostProcessor

<beans>         
    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>     
</beans>
Spring如何解决循环依赖?(单例的设置循环依赖)
  • 循环依赖–>循环引用。—>即2个或以上bean 互相持有对方,最终形成闭环。
  • spring mvc 设置超时时间 spring mvc dao_动态代理_02


  • spring mvc 设置超时时间 spring mvc dao_动态代理_03

  • 构造器的循环依赖。【这个Spring解决不了】
  • 【setter循环依赖】field属性的循环依赖【setter方式 单例,默认方式–>通过递归方法找出当前Bean所依赖的 Bean,然后提前缓存【会放入Cache中】起来。通过提前暴露 -->暴露一个exposedObject用于返回提前暴露的Bean。】
  • Spring的单例对象的初始化主要分为三步:
  • spring mvc 设置超时时间 spring mvc dao_mvc_04

  • (1)createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象
    (2)populateBean:填充属性,这一步主要是多bean的依赖属性进行填充
    (3)initializeBean:调用spring xml中的init 方法。
  • 从上面单例bean的初始化可以知道:循环依赖主要发生在第一、二步,也就是构造器循环依赖和field循环依赖。那么我们要解决循环引用也应该从初始化过程着手,对于单例来说,在Spring容器整个生命周期内,有且只有一个对象,所以很容易想到这个对象应该存在Cache中,Spring为了解决单例的循环依赖问题,使用了三级缓存。
    这三级缓存分别指:
    singletonFactories : 单例对象工厂的cache
    earlySingletonObjects :提前暴光的单例对象的Cache
    singletonObjects:单例对象的cache
Spring 框架中使用到了大量的设计模式,下面列举了比较有代表性的:
  • 代理模式—在 AOP 和 remoting 中被用的比较多。
  • 单例模式—在 spring 配置文件中定义的 bean 默认为单例模式。
  • 模板方法—用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
  • 前端控制器—Spring 提供了 DispatcherServlet 来对请求进行分发。
  • 视图帮助(View Helper )—Spring 提供了一系列的 JSP 标签,高效宏来辅助将分散的代码 整合在视图里。
  • 依赖注入—贯穿于 BeanFactory / ApplicationContext 接口的核心理念。
  • 工厂模式—BeanFactory 用来创建对象的实例。
构造方法注入和设值注入有什么区别?
  • 请注意以下明显的区别:
  1. 在设值注入方法支持大部分的依赖注入,如果我们仅需要注入 int、string 和 long 型的变量,我们不要用设值的方法注入。对于基本类型,如果我们没有注入的话,可以为基本类型设置默认值。在构造方法 注入不支持大部分的依赖注入,因为在调用构造方法中必须传入正确的构造参数,否则的话会报错。
  2. 设值注入会重写构造注入的值。如果我们对同一个变量同时使用了构造方法注入又使用了设置方法注入的话,那么构造方法将不能覆盖由设值方法注入的值。很明显,因为构造方法在对象被创建时调用。
  3. 设值注入有可能还不能保证某种依赖是否已经被注入,也就是说这时对象的依赖关系有可能是不完整的,而构造注入则不允许生成依赖关系不完整的对象。
  4. 在设值注入时如果对象 A 和对象 B 互相依赖,在创建对象 A 时 Spring 会抛出ObjectCurrentlyInCreationException 异常,因为在 B 对象被创建之前 A 对象是不能被创建的,反之亦然。所以 Spring 用设值注入的方法解决了循环依赖的
    问题,因对象的设值方法是在对象被创建之前被调用的。
Spring事务的传播机制(7种)
  • 所谓事务传播机制,也就是事务在多个方法的调用中是如何传递的,是重新创建事务还是使用父方法的事务?父方法的回滚对子方法的事务是否有影响?这些都是可以通过事务传播机制来决定的。
  1. REQUIRED:如果有事务则加入事务,如果没有事务,则创建一个新的事务(默认值);
  2. NOT_SUPPORTED:Spring不为当前方法开启事务,相当于没有事务;
  3. REQUIRES_NEW:不管是否存在事务,都创建一个新的事务,原来的方法挂起,新的方法执行完毕后,继续执行老的事务;
  4. MANDATORY: 必须在一个已有的事务中执行,否则报错;
  5. NEVER: 必须在一个没有的事务中执行,否则报错;
  6. SUPPORTS: 如果其他bean调用这个方法时,其他bean声明了事务,则就用这个事务,如果没有声明事务,那就不用事务;
  7. NESTED: 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与REQUIRED类似的操作
  • Spring 的事务隔离级别(5种)
    Spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致:
  1. ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
  2. ISOLATIONREADUNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
  3. ISOLATIONREADCOMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
  4. ISOLATIONREPEATABLEREAD:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
  5. ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
Spring注入bean的方式
  1. Spring基于xml注入bean:
  • set方法注入;
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
    <property name="springDao" ref="springDao"></property>
</bean>

<bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>
  • 构造器注入:①通过index设置参数的位置;②通过type设置参数类型;
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
    <constructor-arg ref="springDao"></constructor-arg>
    <constructor-arg ref="user"></constructor-arg>
</bean>

<bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>

<bean name="user" class="com.bless.springdemo.vo.User"></bean>
  • 静态工厂注入;
public class DaoFactory {
    //静态工厂
    public static final FactoryDao getStaticFactoryDaoImpl(){
        return new StaticFacotryDaoImpl();
    }
}


public class SpringAction {
    //注入对象
    private FactoryDao staticFactoryDao;
    public void staticFactoryOk(){
        staticFactoryDao.saveFactory();
    }
    //注入对象的set方法
    public void setStaticFactoryDao(FactoryDao staticFactoryDao) {
        this.staticFactoryDao = staticFactoryDao;
    }
}
<bean name="springAction" class="com.bless.springdemo.action.SpringAction" >
    <property name="staticFactoryDao" ref="staticFactoryDao"></property>
</bean>

<!--此处获取对象的方式是从工厂类中获取静态方法-->
<bean name="staticFactoryDao" class="com.bless.springdemo.factory.DaoFactory" 
    factory-method="getStaticFactoryDaoImpl"></bean>
  • 实例工厂注入;
public class DaoFactory {
    
    //实例工厂
    public FactoryDao getFactoryDaoImpl(){
        return new FactoryDaoImpl();
    }
}


public class SpringAction {
    
    //注入对象
    private FactoryDao factoryDao;

    public void factoryOk(){
        factoryDao.saveFactory();
    }

    public void setFactoryDao(FactoryDao factoryDao) {
        this.factoryDao = factoryDao;
    }
}
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">
    <property name="factoryDao" ref="factoryDao"></property>
</bean>

<!--此处获取对象的方式是从工厂类中获取实例方法-->
<bean name="daoFactory" class="com.bless.springdemo.factory.DaoFactory"></bean>
<bean name="factoryDao" factory-bean="daoFactory" factory-method="getFactoryDaoImpl"></bean>
  1. Spring基于注解注入bean
  • bean 的申明、注册
    @Component //注册所有bean
    @Controller //注册控制层的bean
    @Service //注册服务层的bean
    @Repository //注册dao层的bean
  • bean 的注入
    @Autowired 作用于 构造方法、字段、方法,常用于成员变量字段之上,默认ByType
    @Autowired + @Qualifier 注入,指定 bean 的名称
    @Resource JDK 自带注解注入,可以指定 bean 的名称和类型等,通过ByName
Spring Aop两种配置:注解方式和xml配置
  • xml配置
<!-- 加强类 -->
<bean id="userDao" class="cn.ytk.dao.UserDao"></bean>
<bean id="userService" class="cn.ytk.service.UserService">
    <property name="userDao" ref="userDao"></property>
</bean>

<!-- 增强类 -->
<bean id="project" class="cn.ytk.strong.Project"></bean>

<!-- 配置切点和切面 -->
<aop:config>
    <aop:pointcut expression="execution(* cn.ytk.dao.UserDao.*(..))" id="pointcut1"/>
        <aop:aspect ref="project">
            <aop:before method="before1" pointcut-ref="pointcut1"/>
            <aop:after-returning method="after1" pointcut-ref="pointcut1"/>
            <aop:around method="around" pointcut-ref="pointcut1"/>
    </aop:aspect>
</aop:config>
  • 注解方式
<!-- 开启aop的注解 -->
<aop:aspectj-autoproxy/>
<context:component-scan base-package="cn.ytk.*"></context:component-scan>
<!-- 增强类 -->
package cn.ytk.strong;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class Project2 {
    
    //方式1:
    @Before(value="execution(* cn.ytk.dao.UserDao.*(..))")
    public void before() {
        System.out.println("前置通知。。。。。。");
    }

    //方式2:先编写切点在将切点加到加强上。
    @Pointcut("execution(* cn.ytk.dao.*.*(..))")
    public void after() {}
    
    @AfterReturning("after()")
    public void after1() {
        System.out.println("....后置通知....");
        
    }

}
  • 关于集中切入点的设置:
    execution(* com.aptech.jb.epet.dao.hibimpl..(…))
    这样写应该就可以了
    这是com.aptech.jb.epet.dao.hibimpl 包下所有的类的所有方法。。
    第一个代表所有的返回值类型
    第二个
    代表所有的类
    第三个*代表类所有方法
    最后一个…代表所有的参数。
  • 五种调用通知的方式:
  1. ( 前置通知)Before 在方法被调用之前调用通知;
  2. ( 后置通知)After 在方法完成之后调用通知,无论方法执行是否成功;
  3. ( 返回后通知)After-returning 在方法成功执行之后调用通知;
  4. ( 抛出异常后通知)After-throwing 在方法抛出异常后调用通知;
  5. ( 环绕通知)Around 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为;
Spring MVC流程
  • 工作原理
  1. 用户发送请求至前端控制器DispatcherServlet。
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。
  3. 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
  4. DispatcherServlet调用HandlerAdapter处理器适配器。
  5. HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
  6. Controller执行完成返回ModelAndView。
  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
  9. ViewReslover解析后返回具体View。
  10. DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
  11. DispatcherServlet响应用户。
  • 组件说明:
    以下组件通常使用框架提供实现:
    DispatcherServlet:作为前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。
    HandlerMapping:通过扩展处理器映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
    HandlAdapter:通过扩展处理器适配器,支持更多类型的处理器。
    ViewResolver:通过扩展视图解析器,支持更多类型的视图解析,例如:jsp、freemarker、pdf、excel等。
  • 组件:
  1. 前端控制器DispatcherServlet(不需要工程师开发),由框架提供
    作用:接收请求,响应结果,相当于转发器,中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。
  2. 处理器映射器HandlerMapping(不需要工程师开发),由框架提供
    作用:根据请求的url查找Handler,HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
  3. 处理器适配器HandlerAdapter
    作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
    通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
  4. 处理器Handler(需要工程师开发)
    注意:编写Handler时按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler,Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
    由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler。
  5. 视图解析器View resolver(不需要工程师开发),由框架提供
    作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
    View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。
  6. 视图View(需要工程师开发jsp…)
    View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf…)
  • 核心架构的具体流程步骤如下:
  1. 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制;
  2. DispatcherServlet——>HandlerMapping, HandlerMapping 将会把请求映射为HandlerExecutionChain 对象(包含一个Handler 处理器(页面控制器)对象、多个HandlerInterceptor 拦截器)对象,通过这种策略模式,很容易添加新的映射策略;
  3. DispatcherServlet——>HandlerAdapter,HandlerAdapter 将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器;
  4. HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView 对象(包含模型数据、逻辑视图名);
  5. ModelAndView的逻辑视图名——> ViewResolver, ViewResolver 将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术;
  6. View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术;
  7. 返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。
  • 下边两个组件通常情况下需要开发:
    Handler:处理器,即后端控制器用controller表示。
    View:视图,即展示给用户的界面,视图中通常需要标签语言展示模型数据。
    MVC:MVC是一种设计模式
    MVC的原理图:

    M-Model 模型(完成业务逻辑:有javaBean构成,service+dao+entity);
    V-View 视图(做界面的展示 jsp,html……);
    C-Controller 控制器(接收请求—>调用模型—>根据结果派发页面)。