美文网首页
通过类比JDK创建对象的方式学习SpringIoC

通过类比JDK创建对象的方式学习SpringIoC

作者: 乙腾 | 来源:发表于2020-09-20 20:42 被阅读0次

overview

SpringIoc控制反转,将创建对象的权力交给Spring容器,那么可以类比jdk,jdk中所有创建对象的方式在Spring中也同样支持。

SpringIoC的两个基本功能

  1. 通过描述管理Bean,包括装配和获取Bean;
  2. 依赖注入

对象的装配

这里通过类比jdk创建对象的方式来理解SpringIoc装配对象的方式。
jdk创建对象方式:
1.无参构造 new UserDto();
2.有参构造 new UserDto(1,"xxx");
接下来按照以上两种方式来创建对象

无参构造

package com.pl.spring5.demo.config;

import com.pl.spring5.demo.dto.UserDto;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * <p>
 *
 * @Description: TODO
 * </p>
 * @ClassName AppConfig
 * @Author pl
 * @Date 2020/9/20
 * @Version V1.0.0
 */
@Configuration
public class AppConfig {

    @Bean("simpleUser")
    public UserDto getSimpleUser(){
        return new UserDto();
    }
}

有参构造

package com.pl.spring5.demo.config;

import com.pl.spring5.demo.dto.UserDto;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

/**
 * <p>
 *
 * @Description: TODO
 * </p>
 * @ClassName AppConfig
 * @Author pl
 * @Date 2020/9/20
 * @Version V1.0.0
 */
@Configuration
public class AppConfig {

    @Bean("simpleUser")
    public UserDto getSimpleUser(){
        return new UserDto();
    }

    @Value("${demo.constant.user.age}")
    private int age;

    @Value("${demo.constant.user.name}")
    private String name;

    @Bean("ComplexUser")
    public UserDto getComplexUser(){
        return new UserDto(age,name);
    }
}

单元测试

package com.pl.spring5.demo.ioc;

import com.pl.spring5.demo.DemoApplication;
import com.pl.spring5.demo.config.AppConfig;
import com.pl.spring5.demo.dto.UserDto;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.PropertySource;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * <p>
 *
 * @Description: TODO
 * </p>
 * @ClassName IocTest
 * @Author pl
 * @Date 2020/9/20
 * @Version V1.0.0
 */
@SpringBootTest
public class IocTest {

    @Autowired
    @Qualifier("ComplexUser")
    private UserDto complexUser;

    @Autowired
    @Qualifier("simpleUser")
    private UserDto simpleUser;

    @Test
    public void test1(){
        System.out.println(complexUser);
        System.out.println(simpleUser);
    }
}
image.png

SpringBoot中可以实现装配的注解

1.@ComponetScan和@Componet

使用介绍

  • @ComponetScan
    这个注解需要和@Configuration结合使用
    130347218.png
    标明采用何种策略去扫描bean
    策略比如:扫描哪些包,或者排除哪些包
130536218.png
  • @Componet

    这个注解标明哪个类被扫描到SpringIoC中,生效的前提也是该类在ComponetScan扫描的范围内

notice:

n1:@Compoonet和@Configuration的区别

@Component与@Configuration都可以作为配置类,两者标注的类和其中的bean都是装配到SpringIoC中,两者主要有以下三点区别:

  • 单例多例:@Component下使用的@Bean都是多例的,而@Configuration下的bean都是单例的。
  • 使用上:@Componet需要配合@ComponetScan使用
  • 使用习惯上:@Configuration更多强调这是个配置文件,配置类,里面会配置很多bean,而@Componet强调当前类会装配到SpringIoC中,不太会刻意的配置很多bean,只会注入当前类需要的属性。

n2:@SpringBootApplication

在该注解中包含了@Component注解

131718156.png

@Component默认会扫描当钱包和其子包中的类,这也是springboot项目中启动类相对其他类位置外方的原因。

2.其他常见的注解

比如 @Controller @Service @Repository也都是有装配作用的注解。</pre>

属性注入

JDK中对象会有很多变量,对应的Spring的Bean的创建也需要将对象中的变量注入到Bean中。

@Autowired

这个注解是基于类型注入的,byType。

只要被其修饰,该注解就会去SpringIoc中寻找与之类型相匹配的对象实例。

code
Animal

package com.pl.spring5.demo.domain.animal;

/**
 * @Auther: pl
 * @Date: 2020/9/20 18:56
 * @Description:
 */
public interface Animal {
    void use();
}

Person

package com.pl.spring5.demo.domain.animal;

/**
 * @Auther: pl
 * @Date: 2020/9/20 19:37
 * @Description:
 */
public interface Person {

    public void service();


}

Dog

package com.pl.spring5.demo.domain;

import com.pl.spring5.demo.domain.animal.Animal;
import org.springframework.stereotype.Component;

/**
 * <p>
 *
 * @Description: TODO
 * </p>
 * @ClassName Dog
 * @Author pl
 * @Date 2020/9/20
 * @Version V1.0.0
 */
@Component
public class Dog implements Animal {
    @Override
    public void use() {
        System.out.println("你是人类的好朋友");
    }
}

User

package com.pl.spring5.demo.domain;

import com.pl.spring5.demo.domain.animal.Animal;
import com.pl.spring5.demo.domain.animal.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * <p>
 *
 * @Description: TODO
 * </p>
 * @ClassName User
 * @Author pl
 * @Date 2020/9/20
 * @Version V1.0.0
 */
@Component
    public class User implements Person {

    @Autowired
    private Animal animal = null;

    @Override
    public void service() {
        this.animal.use();
    }


}

Junit

package com.pl.spring5.demo.ioc;

import com.pl.spring5.demo.DemoApplication;
import com.pl.spring5.demo.config.AppConfig;
import com.pl.spring5.demo.domain.animal.Person;
import com.pl.spring5.demo.dto.UserDto;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.PropertySource;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * <p>
 *
 * @Description: TODO
 * </p>
 * @ClassName IocTest
 * @Author pl
 * @Date 2020/9/20
 * @Version V1.0.0
 */
@SpringBootTest
public class IocTest {
    
    //@Autowired  按照类型查找,虽然修饰的是User,但是User实现了Person接口,都是一类,所以可以写Person,java中多态的体现。
    @Autowired
    private Person user;

    @Test
    public void test2(){
        user.service();
    }
}
133231703.png

notice:

@Autowired标注方法

133411406.png

他会使用setAnimal方法,在SpringIoC中找到对应的动物注入。

@Autowired标注方法的参数

133563046.png

总结:

@Autowired的作用就是按照类型注入,被他标注的属性,方法(方法中的引用类),方法参数都会被注入。

消除歧义的注入

@Primary和@Quelifiler

比如如果再有一个Cat类实现Animal接口,那么用@Autowired就注入不了了


133940203.png 133945750.png

因为Cat和Dog都属于Animal,属于一类,SpringIoC就不知道需要注入的是哪个类的实例。这时就需要消除歧义的注入了。

@Primary

标注的类,优先注入。

package com.pl.spring5.demo.domain;

import com.pl.spring5.demo.domain.animal.Animal;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

/**
 * <p>
 *
 * @Description: TODO
 * </p>
 * @ClassName Dog
 * @Author pl
 * @Date 2020/9/20
 * @Version V1.0.0
 */
@Component
@Primary
public class Dog implements Animal {
    @Override
    public void use() {
        System.out.println("你是人类的好朋友");
    }
}

但是如果Cat也标注,那么还是不知到谁该注入

@Quelifiler

byName,按照名字注入

他和@Autowired一起使用,按照类型和名字匹配出一个符合条件的注入对象


134233328.png

属性普通类型变量注入

134388390.png

notice

bean的获取:

其实依赖注入中的@Autowired,@Primary,@Quelifiler标注的对象,就是bean的获取

也可以通过AnnotationConfigApplicationContext 获取bean,但是如果bean中有属性注入,@value标注的属性,这样获取就会报错,,@value修饰的属性值就会是${demo.constant.user.name}这样一个string类型的值,而不是配置文件中的值。

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
UserDto simpleUser = (UserDto) ctx.getBean("simpleUser");
System.out.println(simpleUser);

如果装配的对象中有引用类型,会先去注入引用类型

134892578.png

会先注入UserDAO,即先装配UserDAO。

相关文章

网友评论

      本文标题:通过类比JDK创建对象的方式学习SpringIoC

      本文链接:https://www.haomeiwen.com/subject/sevpyktx.html