干货分享

Java分析之Spring bean注入

2020-09-15  本文已影响0人  小白菜aaa

前言

本文主要介绍Spring bean注入的大概过程,废话不多说让我们进入正文。

使用配置注入对象

向beans.xml注入bean:

<bean id="person" class="com.enjoy.cap1.Person">
    <property name="name" value="james"></property>
    <property name="age" value="19"></property>
</bean>

获取bean

//把beans.xml的类加载到容器
ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
//从容器中获取bean
Person person = (Person) app.getBean("person");

使用配置类注入对象

@Configuration
public class MainConfig {
    //给容器中注册一个bean, 类型为返回值的类型, 
    @Bean("abcPerson")
    public Person person01(){
        return new Person("james",20);
    }
}

获取bean

//把配置类中的bean加载到容器
ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
//从容器中获取bean,只用@Bean 则 bean ID 默认取方法名,即person01
Person person = (Person) app.getBean("abcPerson");

使用注解注入对象

配置类添加扫面包注解,将指定包中的类加载到容器

@Configuration
@ComponentScan(value="com.enjoy.cap2")
public class Cap2MainConfig {
    //给容器中注册一个bean, 类型为返回值的类型, 
    @Bean
    public Person person01(){
        return new Person("james",20);
    }
}

添加注解

@Controller
public class OrderController { }

@Service
public class OrderService { }

@Repository
public class OrderDao{ }    

获取bean

//把配置类中的bean加载到容器
ApplicationContext app = new AnnotationConfigApplicationContext(Cap2MainConfig.class);
//Spring 容器中所有 JavaBean 的名称,注解不指定bean ID 则默认取类名,且首字母小写
String[] beanDefinitionNames = app.getBeanDefinitionNames();

配置类添加扫描包注解,将指定包中的类加载到容器

@Configuration
@ComponentScan(value="com.enjoy.cap2")
public class Cap2MainConfig {
    //给容器中注册一个bean, 类型为返回值的类型, 
    @Bean
    public Person person01(){
        return new Person("james",20);
    }
}

添加注解

@Controller
public class OrderController { }

@Service
public class OrderService { }

@Repository
public class OrderDao{ }    

获取bean

//把配置类中的bean加载到容器
ApplicationContext app = new AnnotationConfigApplicationContext(Cap2MainConfig.class);
//Spring 容器中所有 JavaBean 的名称,注解不指定bean ID 则默认取类名,且首字母小写
String[] beanDefinitionNames = app.getBeanDefinitionNames();

定制包扫描时的过滤规则

//@ComponentScan value:指定要扫描的包
//excludeFilters = Filter[] 指定扫描的时候按照什么规则排除那些组件
//includeFilters = Filter[] 指定扫描的时候只需要包含哪些组件
//useDefaultFilters = false 默认是true,扫描所有组件,includeFilters 要改成false,excludeFilters则是true
//----扫描规则如下
//FilterType.ANNOTATION:按照注解
//FilterType.ASSIGNABLE_TYPE:按照给定的类型;比如按BookService类型
//FilterType.ASPECTJ:使用ASPECTJ表达式
//FilterType.REGEX:使用正则指定
//FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口

@Configuration
@ComponentScan(value = "com.enjoy.cap2", includeFilters = {
    @Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
    @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {OrderService.class})
}, useDefaultFilters = false)
public class Cap2MainConfig { }

@Configuration
@ComponentScan(value="com.enjoy.cap2",excludeFilters={
        @Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
        @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {OrderService.class})
})
public class Cap2MainConfig { }

添加注解

@Controller
public class OrderController { }

@Service
public class OrderService { }

@Repository
public class OrderDao{ }    

获取bean

//把配置类中的bean加载到容器
ApplicationContext app = new AnnotationConfigApplicationContext(Cap2MainConfig.class);
//Spring 容器中所有 JavaBean 的名称,注解不指定bean ID 则默认取类名,且首字母小写
String[] beanDefinitionNames = app.getBeanDefinitionNames();

FilterType.CUSTOM的例子

public class JamesTypeFilter implements TypeFilter {
    private ClassMetadata classMetadata;

    /*
     * MetadataReader:读取到当前正在扫描类的信息
     * MetadataReaderFactory:可以获取到其他任何类信息
     */
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
        //获取当前类注解的信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类信息
        classMetadata = metadataReader.getClassMetadata();
        //获取当前类资源(类的路径)
        Resource resource = metadataReader.getResource();
        String className = classMetadata.getClassName();
        System.out.println("----->" + className);
        if (className.contains("Order")) {//当类包含er字符, 则匹配成功,返回true
            return true;
        }
        return false;
    }
}

@Configuration
@ComponentScan(value="com.enjoy.cap2",includeFilters={
        @Filter(type=FilterType.CUSTOM,classes={JamesTypeFilter.class})
},useDefaultFilters=false)
public class Cap2MainConfig { }

添加注解

@Controller
public class OrderController { }

@Service
public class OrderService { }

@Repository
public class OrderDao{ }    

获取bean

//把配置类中的bean加载到容器
ApplicationContext app = new AnnotationConfigApplicationContext(Cap2MainConfig.class);
//Spring 容器中所有 JavaBean 的名称,注解不指定bean ID 则默认取类名,且首字母小写
String[] beanDefinitionNames = app.getBeanDefinitionNames();

单例多例

@Configuration
public class Cap3MainConfig {
    //给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
    @Bean
    public Student student(){
        return new Student("jack",20);
    }

    /*
     * prototype:多实例: IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象, 而是每次获取的时候才会调用方法创建对象
     * singleton:单实例(默认):IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿(大Map.get)的同一个bean
     * request: 主要针对web应用, 递交一次请求创建一个实例
     * session:同一个session创建一个实例
     */
    @Scope("prototype")
    @Bean
    public Person person(){
        return new Person("james",20);
    }
}

验证

    AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap3MainConfig.class);
    //从容器中分别取两次person实例, 看是否为同一个bean
    Object bean1 = app.getBean("person");
    Object bean2 = app.getBean("person");
    System.out.println(bean1 == bean2);
    //从容器中分别取两次student实例, 看是否为同一个bean
    Object student1 = app.getBean("student");
    Object student2 = app.getBean("student");
    System.out.println(student1 == student2);

延迟加载

@Configuration
public class Cap4MainConfig {
    /*
     * 懒加载: 主要针对单实例bean:默认在容器启动的时候创建对象
     * 懒加载:容器启动时候不创建对象, 仅当第一次使用(获取)bean的时候才创建被初始化
     */
    @Lazy
    @Bean
    public Person person(){
        System.out.println("给容器中添加person.......");
        return new Person("james",20);
    }
}

验证

AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap4MainConfig.class);
System.out.println("IOC容器创建完成........");
app.getBean("person");//执行获取的时候才创建并初始化bean

@Conditional条件注册bean

@Configuration
public class Cap5MainConfig {
    @Bean("person")
    public Person person(){
        System.out.println("给容器中添加person.......");
        return new Person("person",20);
    }

    @Conditional(WinCondition.class)
    @Bean("lison")
    public Person lison(){
        System.out.println("给容器中添加lison.......");
        return new Person("Lison",58);
    }

    @Conditional(LinCondition.class)
    @Bean("james")
    public Person james(){
        System.out.println("给容器中添加james.......");
        return new Person("james",20);
    }
}

public class WinCondition implements Condition{
    /**
     *
     * @param context ConditionContext: 判断条件可以使用的上下文(环境)
     * @param metadata AnnotatedTypeMetadata: 注解的信息
     * @return
     */
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // TODO 是否为WINDOW系统
        //能获取到IOC容器正在使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //获取当前环境变量(包括我们操作系统是WIN还是LINUX??)
        Environment environment = context.getEnvironment();
        String osName = environment.getProperty("os.name");
        if(osName.contains("Windows")){
            return true;
        }
        return false;
    }
}

public class LinCondition implements Condition{
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // TODO 是否为WINDOW系统
        //能获取到IOC容器正在使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //获取当前环境变量(包括我们操作系统是WIN还是LINUX??)
        Environment environment = context.getEnvironment();
        String osName = environment.getProperty("os.name");
        if(osName.contains("linux")){
            return true;
        }
        return false;
    }
}

验证

//通过打印语句判断配置是否生效
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap5MainConfig.class);
System.out.println("IOC容器创建完成........");

结尾

感谢看到最后的朋友,都看到最后了,点个赞再走啊,如有不对之处还请多多指正。

上一篇 下一篇

猜你喜欢

热点阅读