美文网首页
srping boot:IOC

srping boot:IOC

作者: 远方的橄榄树 | 来源:发表于2019-12-08 14:38 被阅读0次

准备

java版本:java8
spring boot版本:2.1.10

构建spring boot项目,添加lombok依赖

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

1、组件注册

a. @Configuration和@Bean给容器中注册组件

构建实体类Person.class

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {

    private String name;

    private Integer age;
}

注入组件

@Configuration // 告诉spring这是一个配置类
public class MainConfig {

    /**
     *给spring容器注册一个bean,默认bean的id为方法名称,即“mike”
     */
    @Bean
    public Person mike() {
        return new Person("麦克", 21);
    }

    @Bean
    public Person jack() {
        return new Person("杰克", 13);
    }
}

测试

    @Test
    public void PersonBeanTest() {
        // 获取MainConfig.class的上下文环境
        ApplicationContext context =
                new AnnotationConfigApplicationContext(MainConfig.class);

//        若MainConfig.class中存在多个Person的bean会抛出异常
//        Person mike = context.getBean(Person.class); // error
//        System.out.println(mike);

        Person mike = context.getBean("mike", Person.class); // 根据id获取bean
        System.out.println(mike); // Person(name=麦克, age=21)

        String[] beanNames = context.getBeanNamesForType(Person.class); // 获取bean名称列表
        System.out.println(Arrays.toString(beanNames)); // [mike, jack]
    }

b. @ComponentScan自动扫描组件

//value指定扫描包的路径
@ComponentScan(value = "com.smallbear.springcoredemo.config")
public class ScanConfig {
}

测试

    @Test
    public void componentScanTest() {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(ScanConfig.class);
        String[] beanNames = context.getBeanDefinitionNames(); // 获取扫描到的组件名称
        for (String s : beanNames) {
            System.out.println(s); // scanConfig、mainConfig、mike、jack,还有几个spring自身的组件
        }
    }

c. @Scope设置组件作用域

MainConfig.class中添加组件

    //默认为单实例(singleton),程序启动的时候便会调用该方法将生成的对象实例注入到ioc容器中
    @Scope
    @Bean
    public Person tom() {
        System.out.println("注册组件tom");
        return new Person("汤姆", 41);
    }

    //多实例模式,ioc容器启动时并不会立即创建对象,每次获取的时候会调用该方法创建一个对象
    @Scope("prototype")
    @Bean
    public Person snow() {
        System.out.println("注册组件snow");
        return new Person("雪诺", 31);
    }

测试

    @Test
    public void scopeTest() {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(MainConfig.class);

        System.out.println("获取组件...");
        Person tom1 = context.getBean("tom", Person.class);
        Person tom2 = context.getBean("tom", Person.class);
        System.out.println("tom1==tom2: " + (tom1 == tom2));
        Person snow1 = context.getBean("snow", Person.class);
        Person snow2 = context.getBean("snow", Person.class);
        System.out.println("snow1==snow2: " + (snow1 == snow2));
    }
/*
print result:
注册组件tom
获取组件...
tom1==tom2: true
注册组件snow
注册组件snow
snow1==snow2: false
*/

d. @Import快速的给容器导入一个组件

创建一个实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Color {
    private String name;
}

MainConfig.java类上添加注解@Import({Color.class})便成功将Color.class注册到容器中,组件名称为com.smallbear.springcoredemo.entity.Color

e. @Conditional按照条件注册bean

实现Condition接口

public class WindowsCondition implements Condition {

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        String property = environment.getProperty("os.name");
        System.out.println(property); // Windows 7
        return property != null && property.contains("Windows");
    }
}

MainConfig.class注入bean

    /**
     *若操作系统是Windows系统,则注入bill组件
     */
    @Conditional(WindowsCondition.class)
    @Bean
    public Person bill() {
        return new Person("比尔盖茨", 65);
    }

f. 使用FactoryBean注册组件

public class ColorFactoryBean implements FactoryBean<Color> {

    @Override
    public Color getObject() throws Exception {
        return new Color("red");
    }

    @Override
    public Class<?> getObjectType() {
        return Color.class;
    }

    /**
     * 是否是单实例, FactoryBean接口的默认返回true
     */
    @Override
    public boolean isSingleton() {
        return true;
    }
}

MainConfig.class中注入bean

    @Bean
    public ColorFactoryBean colorFactoryBean() {
        return new ColorFactoryBean();
    }

测试

    @Test
    public void factoryBeanTest() {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(MainConfig.class);

        //容器中注入的是colorFactoryBean组件,但获取的时候返回的是color对象
        Color color = context.getBean("colorFactoryBean", Color.class);
        System.out.println(color.getName()); // red
    }

g. 小结

容器中常用的注册bean的方法
1、组件标注注解(@Controller, @Service, @Component, @Repository等)
2、@Bean
3、@Import
4、使用FactoryBean工厂

2、bean的生命周期

a. @Bean指定初始化和销毁方法

@Data
public class Car {

    private String name;

    private BigDecimal price;

    public Car() {
        System.out.println("car constructor...");
    }

    public Car(String name, BigDecimal price) {
        this.name = name;
        this.price = price;
        System.out.println(this.name + " constructor...");
    }

    public void init() {
        System.out.println(name + " init...");
    }

    public void destroy() {
        System.out.println(name + " destroy...");
    }
}

/**
 * bean的生命周期(由容器来管理):创建---初始化---销毁
 * 可以自定义初始化和销毁方法
*/
@Configuration
public class MainConfigOfLifeCycle {

    /**
     *指定容器的初始化和销毁方法
     * 1、单实例
     * 初始化:对象创建完成时调用
     * 销毁:容器关闭时调用
     */
    @Bean(initMethod = "init", destroyMethod = "destroy")
    public Car benz() {
        return new Car("奔驰", BigDecimal.valueOf(200000));
    }

    /**
     * 2、多实例
     * 初始化 获取bean时触发
     * 销毁 不会主动销毁
     */
    @Scope("prototype")
    @Bean(initMethod = "init", destroyMethod = "destroy")
    public Car BYD() {
        return new Car("比亚迪", BigDecimal.valueOf(12000));
    }
}

测试

    @Test
    public void BenzTest() {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器启动完成...");
        Car BYD = context.getBean("BYD", Car.class);
        context.close();
    }
/*
奔驰 constructor...
奔驰 init...
容器启动完成...
比亚迪 constructor...
比亚迪 init...
奔驰 destroy...
*/

b. InitializingBean和DisposableBean

通过InitializingBeanDisposableBean接口实现bean初始化和销毁方法

public class Cat implements DisposableBean, InitializingBean {


    @Override
    public void destroy() throws Exception {
        System.out.println("cat destroy...");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("cat init...");
    }
}

c. @PostConstruct和@PreDestroy

通过@PostConstruct@PreDestroy注解实现bean初始化和销毁方法

public class Dog {
    
    @PostConstruct
    public void init() {
        System.out.println("cat init...");
    }
    
    @PreDestroy
    public void destroy() {
        System.out.println("dog destroy...");
    }
}

d. BeanPostProcessor

BeanPostProcessorBean初始化后置处理器

/**
 * Bean初始化后置处理器
 */
@Component
@ComponentScan("com.smallbear.springcoredemo")
public class MyBeanPostProcessor implements BeanPostProcessor {

    /**
     *初始化之前执行
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "->before init...");
        return bean;
    }

    /**
     * 初始化之后执行
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + "->after init...");
        return bean;
    }
}

测试

    @Test
    public void beanPostProcessorTest() {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(MyBeanPostProcessor.class);
        Car BYD = context.getBean("BYD", Car.class);
        context.close();
    }
/*
print result部分内容:
比亚迪 constructor...
BYD->before init...
比亚迪 init...
BYD->after init..
*/

3. 自动装配

构建新的spring boot项目

a. @Autowired和@Qualifier

@Autowired:自动注入:
1、优先按照类型去容器中查找对应的组件
2、如果有过个相同类型的组件,再将属性名作为id去容器中寻找
@Qualifier:指定需要装配的组件的id

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Pet {
   private String name;
}
@Configuration
@ComponentScan("com.smallbear.springcoredemo2")
public class MainConfigOfAutoWired {

    //注册name为duck、cat、mouse的组件,
    // 由于米奇和杰瑞组件的名称相同,杰瑞组件没有注册到容器中

    @Bean
    public Pet duck() {
        return new Pet("唐老鸭");
    }

    @Bean("cat")
    public Pet cat() {
        return new Pet("汤姆");
    }

    @Bean
    public Pet mouse() {
        return new Pet("米奇");
    }

    @Primary
    @Bean("mouse")
    public Pet mouse2() {
        return new Pet("杰瑞");
    }
}
@Service
public class PetService {

    @Autowired
    private Pet duck; // 注入唐老鸭

    @Qualifier("cat") // 指定需要装配的组件的id
    @Autowired
    private Pet pet; // 此处注入id为cat的组件(汤姆)

    @Autowired
    private Pet mouse; // 注入米奇

    public void printDuck() {
        System.out.println(duck.getName());
    }

    public void printCat() {
        System.out.println(pet.getName());
    }

    public void printMouse() {
        System.out.println(mouse.getName());
    }
}
    @Test
    public void test01() {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(MainConfigOfAutoWired.class);
        PetService petService = context.getBean("petService", PetService.class);

        String[] petNames = context.getBeanNamesForType(Pet.class);
        System.out.println(Arrays.toString(petNames)); // [duck, cat, mouse]
        petService.printDuck(); // 唐老鸭
        petService.printCat(); // 汤姆
        petService.printMouse(); // 米奇
    }

b. 支持@Resource(java规范的注解)

c. 方法、构造器位置的自动装配

@Component
public class MyPet {
    
    private Pet cat;
    
    private Pet mouse;
    
    @Autowired // 注入汤姆
    public MyPet(Pet cat) {
        this.cat = cat;
    }
    
    @Autowired // 注入米奇
    private void setMouse(Pet mouse) {
        this.mouse = mouse;
    }
}

相关文章

网友评论

      本文标题:srping boot:IOC

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