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

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;

/**
 * 

* * @Description: TODO *

* @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;

/**
 * 

* * @Description: TODO *

* @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;

/**
 * 

* * @Description: TODO *

* @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也都是有装配作用的注解。

属性注入

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;

/**
 * 

* * @Description: TODO *

* @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;

/**
 * 

* * @Description: TODO *

* @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;

/**
 * 

* * @Description: TODO *

* @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;

/**
 * 

* * @Description: TODO *

* @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)