spring bean加载方式

84 阅读2分钟

一、加载方式一

- XML方式声明bean

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!--声明自定义bean-->
    <bean id="studyService" class="com.study.service.impl.StudyServiceImpl" scope="singleton"/>
    <!--声明第三方开发bean-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"/>
</beans>

二、加载方式二

1.XML+注解方式声明bean

<?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    https://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">
    
    <!-- 组件扫描,指定加载bean的位置 -->
    <context:component-scan base-package="com.study"/>
 </beans>

2.使用@Component与衍生注解@Controller 、@Service、@Repository进行bean定义

@Service 
 public class StudyServiceImpl implements StudyService {
 }

3.使用@Bean定义第三方bean,并将所在类定义为配置类或Bean

@Component 
public class DbConfig { 
    @Bean 
    public DruidDataSource getDataSource(){ 
        DruidDataSource ds = new DruidDataSource(); 
        return ds; 
    } 
}

三、加载方式三

注解方式声明配置类:通过对包的扫描加载bean

@Configuration 
@ComponentScan("com.study") 
public class SpringConfig { 
    @Bean 
    public DruidDataSource getDataSource(){ 
        DruidDataSource ds = new DruidDataSource(); 
        return ds; 
    } 
}

扩展1

初始化实现FactoryBean接口的类,实现对bean加载到容器之前的批处理操作

public class StudyFactoryBean implements FactoryBean { 
    public Study getObject() throws Exception { 
        Study study = new Study(); 
        // 进行book对象相关的初始化工作 
        return study; 
    } 
    public Class getObjectType() { 
        return Study.class; 
    } 
}
@Configuration
public class SpringConfig { 
    @Bean 
    //显示的表示为配置StudyFactoryBean ,但实际上配置的是Study
    public StudyFactoryBean book(){ 
        return new StudyFactoryBean(); 
    } 
}

扩展2

加载配置类并加载配置文件

@Configuration 
@ComponentScan("com.study") 
@ImportResource("applicationContext-config.xml") 
public class SpringConfig { 
}

扩展3

使用proxyBeanMethods=true调用此方法得到的对象是从容器中获取的而不是重新创建的

@Configuration(proxyBeanMethods = false) 
public class SpringConfig { 
    @Bean 
    public Study study(){ 
        System.out.println("study init ..."); 
        return new Study(); 
    } 
}
public class AppObject { 
    public static void main(String[] args) { 
        ApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class); 
        SpringConfig config = ctx.getBean("Config", Config.class);
        config.study(); 
    } 
}

四、加载方式四

使用@Import注解导入要注入的bean对应的字节码

@Import(student.class) 
public class SpringConfig { }

被导入的bean无需使用注解声明为bean

public class student { }

此形式可以有效的降低源代码与Spring技术的耦合度,在spring技术底层及诸多框架的整合中被大量使用

扩展4

使用@Import注解导入配置类

@Import(DbConfig.class) 
public class SpringConfig { }

五、加载方式五

使用上下文对象在容器初始化完毕后注入bean:AnnotationConfigApplicationContext调用register方法

public class AppImport { 
    public static void main(String[] args) { 
        AnnotationConfigApplicationContext ctx = new    AnnotationConfigApplicationContext(SpringConfig5.class); 
        ctx.register(student.class); 
        String[] names = ctx.getBeanDefinitionNames(); 
        for (String name : names) { 
            System.out.println(name); 
        } 
    } 
}

需要在容器初始化之后才能使用这种方法。若重复加载同一个bean,后加载的将会覆盖前加载的。

六、加载方式六

导入实现了ImportSelector接口的类,实现对导入源的编程式处理

public class MyImportSelector implements ImportSelector { 
    public String[] selectImports(AnnotationMetadata metadata) { 
        // 使用metadata可以获取到导入该类的大量属性,通过对这些属性进行判断,可以达到动态注入bean的效果
        boolean flag = metadata.hasAnnotation("org.springframework.context.annotation.Import");         if(flag){ 
            return new String[]{"com.domain.study"}; 
        } 
        return new String[]{"com.domain.student"}; 
    } 
}

七、加载方式七

导入实现了ImportBeanDefinitionRegistrar接口的类,通过BeanDefinition的注册器注册实名bean,实现对 容器中bean的裁定,例如对现有bean的覆盖,进而达成不修改源代码的情况下更换实现的效果

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { 
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { 
    BeanDefinition beanDefinition = BeanDefinitionBuilder    .rootBeanDefinition(StudyServiceImpl2.class) .getBeanDefinition();     registry.registerBeanDefinition("studyService", beanDefinition); 
    } 
}

八、加载方式八

导入实现了BeanDefinitionRegistryPostProcessor接口的类,通过BeanDefinition的注册器注册实名bean, 实现对容器中bean的最终裁定

public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor { 
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { 
          BeanDefinition beanDefinition = BeanDefinitionBuilder .rootBeanDefinition(BookServiceImpl4.class) .getBeanDefinition();   registry.registerBeanDefinition("bookService", beanDefinition); 
    } 
}