spring core


一.简介:

 1.依赖注入(DI)

    优点:解耦

    Spring 通过应用上下文(Application Context)装载bean的定义,并把它们组装起来。

    Spring应用上下文负责对象的创建和组装。

        ClassPathXmlApplicationContext加载Spring上下文(ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/xxx.xml"),可通过context获取bean)


2. 应用切面

    面向切面编程(aspect-Oriented programming,AOP):可以将遍布应用各处的功能解耦出来,形成可重用的组件。关注点的分离。


3.Bean

    基于Spring的应用中,,应用对象生存于Spring容器中。Spring容器负责创建对象,装配对象,配置他们并管理他们的整个生命周期,从new到finalize()。

    bean可以通过@Component("beanName")或@Named("beanName")来命名。其中@Named是Java依赖注入规范中提供的。

    Spring容器不只有一个,Spring自带了多个容器实现,可以归为两种不同类型:

        --bean工厂:最简单的容器,提供基本DI支持;

        --应用上下文:基于BeanFactory构建,并提供应用框架级别的服务。(应用较多)

    BeanFactory和FactoryBean的区别( https://www.cnblogs.com/redcool/p/6413461.html):

        BeanFactory是一个工厂类,用于管理Bean的一个工厂。BeanFactory是IOC容器的核心接口,负责实例化,定位,配置应用程序中的对象及建立这些对象间的依赖。

        FactoryBean是实现了FactoryBean接口的Bean。根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,若要获取FactoryBean本身需要在id前面加一个&符号。

        

二.装配Bean

    将组件扫描得到的bean和他们的依赖装配在一起

1.自动扫描组件

    @Controller控制器:注入服务

    @Service服务:注入Dao

    @Repository Dao:实现Dao访问

    @Component:把普通的POJO实例化到Spring容器中,相当于配置文件中的

    @Controller,@Service,@Repository,@Component注解的类,并把这些类纳入进Spring容器中进行管理。

    引入Component的扫描组件:

    其中base-package是需要扫描的包(含所有子包)

    可以使用@Configuration替代xml配置,@ComponentScan(basePackages={"",""})指定扫描组件的包及子包下带有@Component注解的类。@ComponentScan默认扫描所在类的包及子包。

    @Controller:用于标注控制层组件

    @Service:用于标注业务层组件

    @Repository:用于标注数据访问层组件,即DAO组件

    @Component:泛指组件,当组件不好归类时,可使用该注解进行标注。

    @Controller,@Service,@Repository,@Component注解的类,并把这些类纳入进Spring容器中进行管理。


2.自动装配

    @Autowired可以用在构造方法和类的方法上。spring会满足方法参数上所声明的依赖。

        -- 如果没有匹配的bean:在应用上下文创建的时候,Spring会抛出异常,为避免异常可以使用@Autowired(required=false)

        -- 有匹配的bean时:若使用了@Autowired(required=false),在代码没有进行null检查时,这个处于未装配状态的属性可能会抛出NullPointException。

    @Inject也可以完成自动装配,是Java依赖注入规范中提供的。

       

三.高级装配

    @Profile("dev")  -----为dev环境 profile装配的bean

        使用Profile首先要将所有不同的bean定义整理到一个活多个Profile中,在将应用部署到每个环境时,要确保对应的Profile处理激活(active)状态,只有当规定的profile被激活时,相应的bean才会被创建。

        使用@Profile注解指定某个bean属于哪一个Profile。

        激活profile方法:

            -- 作为DispatcherServlet的初始化参数;

            -- 作为WEB应用的上下文参数;

            -- 作为JNDI条目;

            -- 作为环境变量;

            -- 作为JVM的系统属性;

            -- 在集成测试类上,使用@ActiveProfiles注解设置:@ActiveProfiles("dev")

    @Conditional(xxxCondition.class)  -----条件化地创建bean

        可以用到带有@Bean注解的方法上,如果给定条件计算结果为true,就会创建这个bean,否则这个bean将会被忽略。

        设置给Conditional的类可以是任意实现了Condition接口的类型,这个接口只需提供matches()方法的实现即可。matches()方法返回true就会创建带有  @Conditional注解的bean。

    @Autowired

        使用自动装配让Spring完全负责将bean引用注入到构造参数和属性中,能够减少装配应用程序组件时所需的显示配置的数量。

        如果有多个bean能够匹配结果时Spring会抛出NoUniqueBeanDefinitionException。

        此时可以将可选bean中的某一个设为首选(@Primary,Primary与@Component或@Bean一起使用)的bean 或使用限定符(@Qualifier("xxxbeanName"),Qualifier与@Autowired一起使用)来帮助Spring将可选的bean范围缩小到只有一个bean。

        Qualifier也可以与@Component或@Bean一起使用,为某一个bean设置beanName即创建自定义的限定符,以防止bean类名修改导致找不到Qualifier指定beanName。


1.bean的作用域

    默认情况下,Spring应用上下文中所有bean都是作为一单例(singleton)的形式创建的。即不管给定的一个bean被注入到其他bean多少次,每次所注入的都是同一个实例。

    当所使用的类是异变的(mutable),他们会保持一些状态,此时重用是不安全的。

    Spring定义了多种作用域,可以基于这些作用域创建bean:

        -- 单例(Singleton):在整个应用中,只创建bean的一个实例;

        -- 原型(Prototype):每次注入或通过Spring应用上下文获取的时候,都会创建一个bean实例;

        -- 会话(Session):在Web应用中,为每个会话创建一个bean实例;

        -- 请求(Request):在Web应用中,为每个请求创建一个bean实例。

    单例是默认作用域,如果要选择其他作用域,要使用@Scope注解,与@Component或@Bean一起使用:

        -- 原型:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)或@Scope("prototype")

        -- 会话:@Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)

        -- 请求:@Scope(value=WebApplicationContext.SCOPE_REQUEST, proxyMode=ScopedProxyMode.INTERFACES)

    当一个会话或者请求作用域的bean(BeanSession)要注入到单例作用域的bean(BeanSingle)中时,会出现一些问题:

        -- BeanSingle在Spring应用上下文加载的时候创建,此时Spring会试图将BeanSession注入到BeanSingle中,而此时BeanSession还不存在(当有用户进入系统,创建会话后才会被创建)。

        -- 系统中可能会存在多个BeanSession,大多数情况下我们不希望注入一个固定的BeanSession到BeanSingle中,而是当前Session中的那个。

        为了解决这个问题,Spring不会将实际的BeanSession注入到BeanSingle中去,而是注入一个BeanSession的代理。这个代理会暴露出和BeanSession相同的方法,BeanSingle会认为它是一个普通的BeanSession。

        @Scope注解有一个proxyMode属性,用于配置代理。有两种方式:

            -- ScopeProxyMode.INTERFACES,这表明该代理会实现BeanSession接口,并将调用 委托给具体的实现bean。这种方法要求BeanSession是一个接口。

            -- ScopeProxyMode.TARGET_CLASS,这表明Spring会使用CGLib生成目标类的扩展的方式来创建代理。这种方式适用于BeanSession是具体的类。

Spring实战笔记:Spring核心(一)_第1张图片

2.运行时值注入

    依赖注入通常是指将一个bean引用注入到另一个bean的属性或构造器参数中。它通常来讲是指将一个对象与另一个对象进行关联。

    依赖注入能够将组件及其协作的其他组件解耦。

    bean的装配另一个方面是将一个值注入到bean的属性或构造器参数中。

    Spring的两种运行时求值的方式:

        -- 属性占位符(Property placeholder):较简单;

        -- Spring表达式语言(SpEL):较强大。

    占位符的形式为使用"${...}"包装的属性名称,使用XML配置Spring context命名空间:







    Spring表达式语言能够以一种强大简洁的方式将值装配到bean属性和构造器参数中,在这个过程中所使用的表达式会在运行时计算得到值。

    SpEL拥有如下特性:

        -- 使用bean的ID来引用bean;

        -- 调用方法和访问对象的属性;

        -- 对值进行算术、关系和逻辑运算;

        -- 正则表达式匹配;

        -- 集合操作。

    SpEL表达式要放到"#{...}"之中: