Spring-基于注解驱动开发-IoC

138 阅读5分钟

一、@Scope 设置组件作用域

  • 默认是单实例
  • prototype 每次获取的时候才会调用方法创建bean
  • singleton IoC容器启动会调用方法创建对象放到IoC容器中,这样每次获取都是相同的
  • request
  • session

二、@Lazy 懒加载

懒加载: 容器启动不创建对象,第一次获取bean的时候才创建对象,并初始化

三、@Conditional 按条件注册Bean

@Conditional 按照一定的条件判断,满足条件给容器中注册bean

四、给容器中注册组件

1. @ComponentScan包扫描+组件标注注解(@Controller/@Service/@Reponitory/@Component)
2. @Configuration + @Bean[导入第三方包里面的组件]
3. @Import[快速给容器中的导入一个组件]
  • @Import(要导入到容器中的组件), 容器中就会自动注册这个组件,id默认是全类名
@Configuration
@Import(value = {Test01.class, Test02.class})
public class MainConfig {

    @Bean(value = "person")
    public Person person01(){
        return new Person("zhangsan", 23);
    }
}
  • ImportSelector接口: 返回需要导入的组件的全类名
// 返回需要导入的组件
public class MyImportSelector implements ImportSelector {

    /**
     * AnnotationMetadata 当前标注@Import注解类的所有注解信息
     *
     * @param importingClassMetadata
     * @return
     */
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // 不要返回null值,会报空指针异常
        return new String[]{"com.aloneness.bean.Test03", "com.aloneness.bean.Test04"};
    }
}
@Configuration
@Import(value = {Test01.class, Test02.class, MyImportSelector.class})
public class MainConfig {

    @Bean(value = "person")
    public Person person01(){
        return new Person("zhangsan", 23);
    }
}
  • ImportBeanDefinitionRegistrar
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * 把所有需要添加到容器中的bean, 调用BeanDefinitionRegistry.registerBeanDefinition() 手工注册进来
     *
     * @param importingClassMetadata AnnotationMetadata 当前类的注册信息
     * @param registry BeanDefinitionRegistry BeanDefinition的注册类
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        boolean definition = registry.containsBeanDefinition("com.aloneness.bean.Test03");
        boolean definition1 = registry.containsBeanDefinition("com.aloneness.bean.Test04");

        if(definition && definition1){
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Test05.class);
            registry.registerBeanDefinition("test05", rootBeanDefinition);
        }
    }
}
@Configuration
@Import(value = {Test01.class, Test02.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig {

    @Bean(value = "person")
    public Person person01(){
        return new Person("zhangsan", 23);
    }
}
4. 使用Spring提供的FactoryBean(工厂Bean)
// 创建一个Spring定义的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {

    // 返回一个Color对象,这个对象会添加到容器中
    @Override
    public Color getObject() throws Exception {
        return new Color();
    }

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

    // true 是单实例 false 是多实例
    @Override
    public boolean isSingleton() {
        return true;
    }
}
@Configuration
@Import(value = {Test01.class, Test02.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MainConfig {

    @Bean(value = "person")
    public Person person01(){
        return new Person("zhangsan", 23);
    }

    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }
}
public class MainTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);

        String[] definitionNames = applicationContext.getBeanDefinitionNames();

        for (String name : definitionNames) {
            System.out.println(name);
        }

        // 工厂Bean获取的是getObject()创建的对象
        Object colorFactoryBean = applicationContext.getBean("colorFactoryBean");
        System.out.println(colorFactoryBean.getClass());  // class com.aloneness.bean.Color

        // 如果需要获取工厂Bean,需要加上前缀&
        Object colorFactoryBean1 = applicationContext.getBean("&colorFactoryBean");
        System.out.println(colorFactoryBean1.getClass());  // class com.aloneness.bean.ColorFactoryBean
    }
}

五、Bean的生命周期

Bean的生命周期: 创建---初始化---销毁的过程, 容器管理bean的生命周期

自定义初始化和销毁方法

构造(对象创建)

  • 单实例:在容器启动的时候创建对象; 创建对象完成,并赋值好,调用初始化方法; 容器关闭的时候调用销毁方法
  • 多实例:在获取Bean的时候创建对象; 调用初始化方法; 容器不会管理这个Bean,不会调用销毁方法
  1. 指定初始化和销毁方法,通过@Bean注解初始化和销毁
public class Car {

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

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

    public void destory(){
        System.out.println("car destory()...");
    }
}
@Configuration
public class MainConfigOfLifeCycle {

    @Bean(initMethod = "init", destroyMethod = "destory")
    public Car car(){
        return new Car();
    }
}
public class MainTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");
        applicationContext.close();
    }
}
// 结果为
car constructor...
car init()...
容器创建完成...
car destory()...
  1. 通过InitializingBean、DisposableBean接口定义初始化,销毁方法
@Component
public class Cat implements InitializingBean, DisposableBean {

    public Cat(){
        System.out.println("cat...构造器...");
    }

    // 初始化, Bean创建完成,并赋值好后
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet...初始化...");
    }
    
    // 销毁方法
    @Override
    public void destroy() throws Exception {
        System.out.println("destroy...销毁...");
    }
}

@Configuration
@ComponentScan("com.aloneness.lifeCycle")
public class MainConfigOfLifeCycle {
}

public class MainTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");
        applicationContext.close();
    }
}

// 结果为
cat...构造器...
afterPropertiesSet...初始化...
容器创建完成...
destroy...销毁...
  1. 可以使用JSR250
  • @PostConstruct: 在bean创建完成并且属性赋值完成,来执行初始化方法
  • @PreDestory: 在容器销毁Bean之前通知我们进行清理工作
@Component
public class Dog {

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

    @PostConstruct
    public void init(){
        System.out.println("Dog...init...");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("Dog...destory");
    }
}

@Configuration
@ComponentScan("com.aloneness.lifeCycle")
public class MainConfigOfLifeCycle {
}

public class MainTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
        System.out.println("容器创建完成...");
        applicationContext.close();
    }
}
// 结果为
Dog constructor...
Dog...init...
容器创建完成...
Dog...destory
  1. BeanPostProcessor接口, Bean的后置处理器, 用来处理Bean创建前后的工作
  • postProcessBeforeInitialization 在初始化之前工作
  • postProcessAfterInitialization 在初始化之后工作
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    /**
     * @param o  bean实例
     * @param s  bean的名字
     * @return 返回bean对象
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessBeforeInitialization...初始化前..." + s + "-->" + o);
        return o;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("postProcessAfterInitialization...初始化后..." + s + "-->" + o);
        return o;
    }
}
// 结果为
cat...构造器...
postProcessBeforeInitialization...初始化前...cat-->com.aloneness.lifeCycle.Cat@101df177
afterPropertiesSet...初始化...
postProcessAfterInitialization...初始化后...cat-->com.aloneness.lifeCycle.Cat@101df177

@Value赋值

  • 基本数值
  • SpEL, #{}
  • 配置文件的值 ${}
    • 引入配置文件@PropertySource(value = {"classpath:person.properties"})
    • @Value("${person.age}") 标注属性

自动装配

  • @Autowired 自动注入
    • 默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class)
    • 如果找到多个相同的类型的组件,再将属性的名称作为组件的id去容器中查找
    • @Qualifier("bookDao"):使用@Qualifier指定需要装配的组件的id,而不是使用属性名
    • 默认一定要将属性赋值好, 否则会出错, 可以使用@Autowired(required = false), 但不推荐
    • @Primary 让Spring进行装配Bean的时候, 首选这个Bean装配
  • 还支持使用@Resource(JSR250) @Inject(JSR330) Java规范
  • 自定义组件想要使用Spring容器底层的一些组件(applicationContext,BeanFactory,xxx)自定义组件实现xxxAware接口 xxxAware:功能使用xxxProcessor

@Profile

  • Profile: Spring 为我们提供的可以根据当前的环境,动态的激活和切换一系列 组件的功能
    1. 命令行参数 -Dspring.profiles.active=test\dev\prod
    1. 使用代码的方式激活
@Configuration
public class MainConfigOfProfile {

    @Profile("dev")
    @Bean
    public DataSource devDataSource() throws PropertyVetoException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setUser("root");
        comboPooledDataSource.setPassword("123456");
        comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
        comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/myshop");
        return comboPooledDataSource;
    }

    @Profile("prod")
    @Bean
    public DataSource prodDataSource() throws PropertyVetoException {
        ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
        comboPooledDataSource.setUser("root");
        comboPooledDataSource.setPassword("123456");
        comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
        comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/myshop");
        return comboPooledDataSource;
    }
}