微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Spring知识点总结篇1 IOC

IOC篇总结

IoC  DI是什么?

 IoC 即控制反转,简单来说就是把原来代码里需要实现的对象创建、依赖反转给容器来帮忙实现,需要创建一个容器并且需要一种描述让容器知道要创建的对象间的关系,在 Spring 中管理对象及其依赖关系是通过 Spring 的 IoC 容器实现的。

控制反转:即我们对象(bean)之间的调用等操作交给了第三方容器来完成,我们将控制权交给对方即为控制反转

DI:依赖注入 

“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。 依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。

 

Spring IoC容器配置Bean的方式?

  • 基于XML文件进行配置。
  • 基于注解进行配置。
  • 基于Java程序进行配置(Spring 3+)

 

 

 

Bean 是如何被管理的?

在Spring框架中,一旦把一个bean纳入到Spring IoC容器之中,这个bean的生命周期就会交由容器进行管理,一般担当管理者角色的是beanfactory或ApplicationContext。认识一下Bean的生命周期活动,对更好的利用它有很大的帮助。 概括来说主要有四个阶段:实例化,初始化,使用,销毁

 

 

 

 

Bean 的生命周期?

在 IoC 容器的初始化过程中会对 Bean 定义完成资源定位,加载读取配置并解析,最后将解析的 Bean 信息放在一个 HashMap 集合中。

当 IoC 容器初始化完成后,会进行对 Bean 实例的创建和依赖注入过程,注入对象依赖的各种属性值,在初始化时可以指定自定义的初始化方法

经过这一系列初始化操作后 Bean 达到可用状态,接下来就可以使用 Bean 了,当使用完成后会调用 destroy 方法进行销毁,此时也可以指定自定义的销毁方法,最终 Bean 被销毁且从容器中移除。

XML 方式通过配置 bean 标签中的 init-Method 和 destory-Method 指定自定义初始化和销毁方法

注解方式通过 @PreConstruct 和 @postconstruct 注解指定自定义初始化和销毁方法

(1)创建bean实例 通过构造器创建bean实例(无参构造) (2)为bean的属性设置值和对其他bean的引用(调用set方法)   (3)  调用bean的初始化的方法(需要进行配置) (4)bean就可使用了 对象获取到来 (5)当容器关闭的时候 调用bean的销毁的方法 (需要进行配置销毁的方法

 

 

 

Spring中Bean的作用域有哪些?

singleton

认情况下,spring的ApplicationContext容器在启动时,自动实例化所有singleton的Bean并缓存于容器中.虽然启动时会花费一些时间,但带来两个好处:首先对Bean提前的实例化操作会及早发现一些潜在的配置问题.其次Bean以缓存的方式保存,当运行时使用到该Bean时就无须再实例化了,加快了运行效率.如果用户不希望在容器启动时提前实例化singleton的Bean,可以通过lazy-init属性进行控制. 单例模式,是认作用域,不管收到多少 Bean 请求每个容器中只有一个唯一的 Bean 实例。

prototype

认情况下,spring容器在启动时不实例化prototype的Bean.此外,spring容器将prototype的Bean交给调用者后,就不再管理它的生命周期. 原型模式,和 singleton 相反,每次 Bean 请求都会创建一个新的实例。

request

每次 HTTP 请求都会创建一个新的 Bean 并把它放到 request 域中,在请求完成后 Bean 会失效并被垃圾收集器回收。  

session

一个HTTP session共享一个Bean,不同HTTP session使用不同的Bean,当HTTP Session结束后,实例才被销毁.该作用域仅适用于webApplicationContext环境 和 request 类似,确保每个 session 中有一个 Bean 实例,session 过期后 bean 会随之失效。

globalSession作用域

一个全局session共享一个Bean,一般用于portlet应用环境,该作用域仅适用于webApplicationContext环境.  

 

如何通过 XML 方式创建 Bean?

认无参构造方法,只需要指明 bean 标签中的 id 和 class 属性,如果没有无参构造方***报错。

静态工厂方法,通过 bean 标签中的 class 属性指明静态工厂,factory-method 属性指明静态工厂方法

实例工厂方法,通过 bean 标签中的 factory-bean 属性指明实例工厂,factory-method 属性指明实例工厂方法

 

 

如何通过注解创建 Bean?

@Component 把当前类对象存入 Spring 容器中,相当于在 xml 中配置一个 bean 标签。value 属性指定 bean 的 id,认使用当前类的首字母小写的类名。

@Controller@Service@Repository 三个注解都是 @Component 的衍生注解,作用及属性都是一模一样的。只是提供了更加明确语义,@Controller 用于控制层,@Service用于业务层,@Repository用于持久层。如果注解中有且只有一个 value 属性要赋值时可以省略 value。

如果想将第三方的类变成组件又没有源代码,也就没办法使用 @Component 进行自动配置,这种时候就要使用 @Bean 注解。被 @Bean 注解的方法返回值是一个对象,将会实例化,配置和初始化一个新对象并返回,这个对象由 Spring 的 IoC 容器管理。name 属性用于给当前 @Bean 注解方法创建的对象指定一个名称,即 bean 的 id。当使用注解配置方法时,如果方法有参数,Spring 会去容器查找是否有可用 bean对象,查找方式和 @Autowired 一样。

@Component 和@Bean的区别

@Component注解表明一个类会作为组件类,并告知Spring要为这个类创建bean。

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

两者的目的是一样的,都是注册bean到spring容器中。

区别:

@Component(@Controller、@Service、@Repository)通常是通过类路径扫描来自动侦测以及自动装配spring容器中。

而@Bean注解通常是我们在标有该注解的方法中定义产生这个bean的逻辑。

@Component 作用于类,@Bean作用于方法

@Component从注解加与类之上,成为组件类,当spring自动扫描或者通过类路径扫描后将其装配到spring容器中,由spring容器自己生成bean

@Bean 加与方法之上,其方法返回的对象注册spring容器中的bean(自己注册并非由容器生成

总结:

@Component和@Bean都是用来注册Bean并装配到spring容器中,但是Bean比Component的自定义性更强。可以实现一些Component实现不了的自定义加载类。



 

如何通过注解配置文件

@Configuration 用于指定当前类是一个 spring 配置类,当创建容器时会从该类上加载注解,value 属性用于指定配置类的字节码。

@ComponentScan 用于指定 Spring 在初始化容器时要扫描的包。basePackages 属性用于指定要扫描的包。

@PropertySource 用于加载 .properties 文件中的配置。value 属性用于指定文件位置,如果是在类路径下需要加上 classpath。

@Import 用于导入其他配置类,在引入其他配置类时可以不用再写 @Configuration 注解。有 @Import 的是父配置类,引入的是子配置类。value 属性用于指定其他配置类的字节码

@Configuration 和@Component区别的简单解释

使用 @Configuration 时,会为该类生成cglib代理对象的子类Class,并对方法拦截,第二次调用xxx方法时直接从beanfactory之中获取对象,所以得到的是同一个对象。
而 @Component 则不会生成 cglib 代理Class,所以多次调用方法 student() 就会生成多个不同的对象。

 

 

 

 

IOC容器初始化过程

基于 XML 的容器初始化

基于注解的容器初始化

分为两种:① 直接将注解 Bean 注册到容器中,可以在初始化容器时注册,也可以在容器创建之后手动注册,然后刷新容器使其对注册的注解 Bean 进行处理。

                ② 通过扫描指定的包及其子包的所有类处理,在初始化注解容器时指定要自动扫描的路径。

 

 

 

 

依赖注入(DI)的实现方法有哪些?

构造方法注入: IoC Service Provider 会检查被注入对象的构造方法,取得它所需要的依赖对象列表,进而为其注入相应的对象。这种方法的优点是在对象构造完成后就处于就绪状态,可以马上使用。缺点是当依赖对象较多时,构造方法的参数列表会比较长,构造方法无法被继承,无法设置认值。对于非必需的依赖处理可能需要引入多个构造方法,参数数量的变动可能会造成维护的困难。

setter 方法注入: 当前对象只需要为其依赖对象对应的属性添加 setter 方法,就可以通过 setter 方法将依赖对象注入到被依赖对象中。setter 方法注入在描述性上要比构造方法注入强,并且可以被继承,允许设置认值。缺点是无法在对象构造完成后马上进入就绪状态。

接口注入: 必须实现某个接口,接口提供方法来为其注入依赖对象。使用少,因为它强制要求被注入对象实现不必要接口,侵入性强。

 

 

依赖注入时如何注入集合属性

可以在定义Bean属性时,通过 <list> / <set> / <map> / <props> 分别为其注入列表、集合、映射和键值都是字符串

 

 

 

 

IOC的优缺点

优点:

降低类之间耦合,可维护性比较好,非常便于进行单元测试,便于调试程序和诊断故障。 模块之间通过接口交流,互不干扰,便于团队开发。 可复用性好 模块具有热插拔特性,可直接修改配置文件。   缺点: 引入了第三方IOC容器,生成对象的步骤变得有些复杂 IOC容器生成对象是通过反射方式,在运行效率上有一定的损耗。 额外的配置工作

 

 

依赖注入的相关注解?

@Autowired自动按类型注入,如果有多个匹配则按照指定 Bean 的 id 查找,查找不到会报错。

@Qualifier:在自动按照类型注入的基础上再按照 Bean 的 id 注入,给变量注入时必须搭配 @Autowired,给方法注入时可单独使用。

@Resource :直接按照 Bean 的 id 注入,只能注入 Bean 类型。

@Value :用于注入基本数据类型和 String 类型。

 

 

 

有哪些常用的 Context?

最常被使用的 ApplicationContext 接口实现:
  • FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径
  • ClasspathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLAsspATH 环境变量即可,因为,容器会从 CLAsspATH 中搜索 bean 配置文件
  • WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。

 

 

 

beanfactoryfactorybean 和 ApplicationContext 的区别?

beanfactory一个 Bean 工厂,使用简单工厂模式,是 Spring IoC 容器顶级接口,可以理解为含有 Bean 集合的工厂类,作用是管理 Bean,包括实例化、定位、配置对象及建立这些对象间的依赖。beanfactory 实例化后并不会自动实例化 Bean,只有当 Bean 被使用时才实例化与装配依赖关系,属于延迟加载,适合多例模式。

factorybean一个工厂 Bean,使用了工厂方法模式,作用是生产其他 Bean 实例,可以通过实现该接口,提供一个工厂方法自定义实例化 Bean 的逻辑。factorybean 接口由 beanfactory 中配置的对象实现,这些对象本身就是用于创建对象的工厂,如果一个 Bean 实现了这个接口,那么它就是创建对象的工厂 Bean,而不是 Bean 实例本身。

ApplicationConext 是 beanfactory 的子接口,扩展了 beanfactory功能,提供了支持国际化的文本消息,统一的资源文件读取方式,事件传播以及应用层的特别配置等。容器会在初始化时对配置的 Bean 进行预实例化,Bean 的依赖注入在容器初始化时就已经完成,属于立即加载,适合单例模式,一般推荐使用。

 

 

 

 

Bean放入spring容器中的常用方式

1、@Configuration + @Bean

这种方式其实,是我们最常用的一种方式,@Configuration用来声明一个配置类,然后使用 @Bean 注解,用于声明一个bean,将其加入到spring容器中。

具体代码如下:

@Configuration
public class MyConfiguration {
    @Bean
    public Person person() {
        Person person = new Person();
        person.setName("spring");
        return person;
    }
}copY

2、@Componet + @ComponentScan

这种方式也是我们用的比较多的方式,@Componet中文译为组件,放在类名上面,然后@ComponentScan放置在我们的配置类上,然后可以指定一个路径,进行扫描带有@Componet注解的bean,然后加至容器中。

具体代码如下:

@Component
public class Person {
    private String name;

    public String getName() {

        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

@ComponentScan(basePackages = "com.springboot.initbean.*")
public class Demo1 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Demo1.class);
        Person bean = applicationContext.getBean(Person.class);
        System.out.println(bean);
    }
}copY

结果输出:

Person{name='null'}

表示成功将Person放置在了IOC容器中。

 

 

 

 

Spring的 IOC 容器比New对象究竟好在哪?

  1. 资源集中管理,实现资源的可配置和易管理。
  2. 降低了使用资源双方的依赖程度,也就是我们说的耦合度

 

 

 

 

 

 

 

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐