Spring IOC之总结篇

 

一、前言

  本人最近刚看完《Spring实战 第四版》这本书,也整理写了一些demo。本着复习和分享的心态,题主从今天开始会陆续分享一些Spring的相关教程,欢迎各位来查看评论。

二、Spring IOC概念解析

  由于网上对Spring IOC的相关概念已经有了很清晰的讲解了,题主在此就不赘述了。这里推荐一篇文章谈谈对Spring IOC的理解,该篇通俗易懂解释了什么是IOC,DI,以及他们之间的区别。

三、Spring IOC装配bean的三种方式

1、自动化装配Bean

     @Component:表明该类会作为普通组件(pojo)类,并告知Spring要为这个类创建Bean。

     @Repository:用于标注数据访问层(dao),特殊的@Component注解

     @Service:用于标注服务层(Service),特殊的@Component注解

     @Controller:用于标注控制层(Controller),特殊的@Component注解

     @ComponentScan:默认会扫描与配置类相同的包及其子包,查找带有@Component注解的类,并创建Bean。

可通过basePackages、basePackageClasses属性设置基础包。(推荐使用basePackageClasses,因为basePackages是类型不安全的)

2、JavaConfig显式配置

   @Configuration:表明此类是一个配置类,该类应该包含在Spring应用上下文中和如何创建Bean的细节。

   @Bean:告诉Spring此方法将会返回一个对象,该对象要注册为Spring应用上下文中的Bean。包含了最终产生bean实例的逻辑。

3、在XML中显式配置

    声明bean:〈bean〉标签,id属性设置Bean的名字,class属性设置Bean的所在类,scope属性可指定单例(singleton默认)或多例(prototype)等。

   构造器注入:元素、使用Spring3.0所引入的c-命名空间。

   设值注入(setter):元素、p-命名空间。

   装配集合:在上诉两种方法中内嵌元素,Spring util-命名空间中的元素(如:

四、Spring IOC依赖注入的三种方式

1、构造器注入 

        构造器注入主要是依赖于构造方法去实现的,构造方法可以是有参也可以是无参,我们在平常都是通过类的构造方法来创建类对象,以及给他赋值,同样Spring 也可以采用反射的方式,通过构造方法来完成注入注入(赋值),这就是构造器注入的原理。

2、Setter注入 

        Setter注入是Spring现在最主流的注入方式,它可以利用Java Bean 规范所定义set/get方法来完成注入,可读性灵活性高,它不需要使用构造器注入时出现的多个参数,它可以把构造方法声明成无参构造,再使用setter注入设置相对应的值,其实也是通过java反射技术去实现的。在这里推荐一个好用的Jar包 Lombok(Lombok简单入门),它可以帮助我们简化一些Java代码的编写。

3、接口注入

      接口注入是需要调用者必须实现一个指定的接口,然后将接口的实现类注入到接口中,这种方式使用比较少。

五、Spring IOC的三种依赖注入注解

1、@Inject:是JSR303中的规范,默认根据类型(Type)进行自动装配的,如果需要按名称进行装配,则需要配合@Named;

2、@AutoWired:是spring自带的注解,默认根据类型(Type)进行自动装配的,如果需要按名称进行装配,则需要配合@Qualifier;

3、@Resource:是JSR250规范的实现,默认根据名称(Name)进行自动装配的,一般会指定一个name属性。

六、导入和混合配置

1、在JavaConfig中引用XML配置:

      @Import:引入带有@Configuration的java类(整合多个javaConfig)

      @ImportResource:导入Spring中的配置文件.xml

 2、在XML配置中引用javaConfig:

       :导入其他的XML配置文件

       :通过将配置类设置成bean导入到XML配置中

七、Bean的作用域

在Spring中Bean总共有5种作用域:

① singleton(单例)默认:使用该属性定义Bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。

② prototype(原型):使用该属性定义Bean时,IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。

//指定原型作用域(比@Scope(“prototype”)方式更加安全) 
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)     

③ request:该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。

④ session:该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。

//指定会话作用域,需设置代理
@Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)   

代理模式:ScopedProxyMode.INTERFACES --> 基于接口的JDK动态代理       

                 ScopedProxyMode.TARGET_CLASS --> 基于类的CGLib代理

当在XML中通过使用元素的scope属性来设置作用域时,可通过来设置代理

⑤ global-session:该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。

八、处理自动装配的歧义性

问题描述:比如说我们有个接口类Animal,而此接口有多个实现类,如Dog,Cat等。此时使用@Autowired注入注解来实现接口注入时,将会抛出NoUniqueBeanDefinitionException异常。

@Autowired
Animal animal;

1、标示首选的Bean(若有多个首选的bean,歧义依然存在)

     @Primary注解可与@Component组合用在组件扫描的bean上,也可以与@Bean组合用在Java配置的bean声明中。在XMl中可通过元素的primary属性来指定首选的bean.

示例:

@Component
@Primary
public class Dog extends Animal(){ .........  }
@Bean
@Primiary
public Animal dog(){
   return  new  Dog();
}

 

2、限定符

   @Qualifier注解可与@Autowired和@Inject协同使用,在注入时指定想注入的是哪个Bean。所设置的参数为想注入的bean的ID。(参数类型为String类型,紧耦合)

示例:

@Autowired
@Qualifier("dog")
Animal animal;

3、创建自定义的限定符(在自定义的注解中使用@Qualifier注解来标注)

常见元注解(元注解:用于创建注解的注解):

@Target,用于描述注解的使用范围

               Constructor:构造器     Field:域             Local_variable:局部变量               Method:方法

               Package:包      Parameter:参数            Type:用于描述类、接口(包括注解类型)、enum声明。

@Retention,用于描述注解的生命周期

               Source:注解只保留在源文件,当java文件编译成class文件时,注解被遗弃。

               Class:注解被保留到class文件,但JVM加载class文件时被遗弃,默认方式。

           Runtime:注解不仅保存到class文件,当JVM加载class文件之后仍存在。

@Documented:指明修饰的注解,可以被例如javadoc此类的工具文档化

@Inherited:允许子类继承父类中的注解

示例: 

@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface Dog{
 
}
@Component
@Dog
public class Dog extends Animal(){ .........  }

九、其他

1、切换开发环境

       软件开发过程一般涉及多个阶段,而每个阶段的环境的配置参数(数据库等)会有所不同。此时我们可以使用profile功能来切换开发环境。

(1)在java中配置profile

     @Profile 注解用于标明当前运行环境,只有当对应的profile被激活时,才将profile中所对应的Bean注册到Spring容器中。

   (注:没有指定profile的bean始终都会被创建)

(2)在XML中配置profile

     通过元素的profile属性配置profile

(3)激活profile

 Spring依赖Spring.profiles.active 和Spring.profiles.default来确定哪个profile处于激活状态。可通过以下方式来设置这两个属性:

作为DispatcherServlet的初始化参数;
作为Web应用的上下文参数;
作为JNDI(java命名与文件夹接口)条目;
作为环境变量;
作为JVM的系统属性;
在集成测试类上,使用@ActiveProfiles注解设置(用来指定运行测试时要激活哪个profile)。

 2、条件化的Bean

@Conditional注解,用到带有@Bean注解的方法上。若给定的条件计算结果为true则创建,否则不创建。

设置给@Conditional的类可以是任意实现了Condition接口的类型。

public interface Condition {
    boolean matches (ConditionContext ctxt , AnnotatedTypeMetadata metadata);
}

ConditionContext是一个接口,大致如下所示:

public interface ConditionContext {
    BeanDefinitionRegistry getRegistry();        //可检查Bean定义
    ConfigurableListableBeanFactory getBeanFactory(); //可检查bean是否存在,甚至探查bean的属性
    Environment getEnvironment();   //可检查环境变量是否存在以及它的值是什么
    ResourceLoader getResourceLoader();     //可读取并探查返回的ResourceLoader所加载的资源
    ClassLoader getClassLoader();     //借助返回的ClassLoader加载并检查类是否存在
}

AnnotatedTypeMetadata则能够让我们检查带有@Bean注解的方法上是否有其他注解:

public interface AnnotatedTypeMetadata {
  boolean isAnnotated(String annotationType); 
  Map getAnnotationAttributes(String annotationType); 
  Map getAnnotationAttributes(String annotationType, boolean classValuesAsString); 
  MultiValueMap getAllAnnotationAttributes(String annotationType); 
  MultiValueMap getAllAnnotationAttributes(String annotationType, boolean classValuesAsString); 
}

      比如,借助isAnnotated()方法,我们能够判断带有@Bean注解的方法是不是还有其他特定的注解。借助其他的方法,我们能够检查@Bean注解的方法上其他注解的属性。

 

      

 

 

 

 

你可能感兴趣的:(Spring,Spring,SpringIOC)