spring创建bean的方式

目录

方式1:xml方式

方式2:注解+xml方式

方式3:纯注解方式: 

FactoryBean方式

proxyBeanMethods属性

@ImportResource注解

方式4:@Import方式:

方式5:手工加载bean

方式6:使用实现类ImportSelector

方式7:使用实现类ImportBeanDefinitionRegistrar

        ImportSelector和ImportBeanDefinitionRegistrar区别:

方式8:实现类BeanDefinitionRegistryPostProcessor


方式1:xml方式

<?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">
    <!--xml声明自定义bean-->
    <bean id="cat" class="com.itheima.bean.Cat"/>
    <bean class="com.itheima.bean.Dog"/>

    <!--xml声明第三方bean-->
    <bean id="druidBean" class="com.alibaba.druid.pool.DruidDataSource"/>
</beans>
public class App1 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext1.xml");
        
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

方式2:注解+xml方式

<?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
                http://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.itheima.bean,com.itheima.config"/>
</beans>
package com.itheima.bean;

import org.springframework.stereotype.Component;

@Component("Tom")
public class Cat {
}
package com.itheima.app;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext2.xml");

        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

方式3:纯注解方式: 

package com.itheima.config;

import org.springframework.context.annotation.ComponentScan;

//  使用配置类方式获取bean时,可以省略@Component或@Configuration
// 当被其他类扫描加载bean时,例如:创建配置类获取第三方bean。不能省略@Component或@Configuration
@ComponentScan({"com.itheima.bean","com.itheima.config"})
public class SpringConfig3 {
}
package com.itheima.app;

import com.itheima.config.SpringConfig3;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App3 {
    public static void main(String[] args) {
        //使用配置类方式获取bean时,会自动创建配置类的bean
        //同DbConfig一样只有创建bean之后,才能获取内部的bean
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig3.class);

        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

FactoryBean方式

package com.itheima.bean;

import org.springframework.beans.factory.FactoryBean;

//泛型中指明使用工厂类创建bean的类型
public class DogFactoryBean implements FactoryBean<Dog> {

    //返回对象
    public Dog getObject() throws Exception {
        Dog dog = new Dog();
        return dog;
    }

    //返回类型
    public Class<?> getObjectType() {
        return Dog.class;
    }

    //是否单例(true 单例 false 非单例)
    public boolean isSingleton() {
        return false;
    }
}
package com.itheima.config;

import com.itheima.bean.DogFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

//  使用配置类方式获取bean时,可以省略@Component或@Configuration。就可以获取到自身类bean和内部定义的bean
//  当被其他类扫描加载bean时,例如:创建配置类DbConfig获取第三方bean数据源Druid。不能省略@Component或@Configuration,必须被容器扫描到才能加载到自身和内部定义的bean
@ComponentScan({"com.itheima.bean","com.itheima.config"})
public class SpringConfig3 {

    //使用实现接口FactoryBean<T>创建出来的是泛型中的bean
    @Bean
    public DogFactoryBean dog(){
        DogFactoryBean dogFactoryBean = new DogFactoryBean();
        return dogFactoryBean;
    }
}
public class App3 {
    public static void main(String[] args) {
        //使用配置类方式获取bean时,会自动创建配置类的bean
        //同DbConfig一样只有创建bean之后,才能获取内部的bean
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig3.class);

        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Dog.class));
        System.out.println(context.getBean(Dog.class));
        System.out.println(context.getBean(Dog.class));

    }
}

5d14148c1f5b4e75aa28e16a8645c9d3.png

通过factoryBean创建的是泛型中的bean对象,单例模式内存地址相同

proxyBeanMethods属性

package com.itheima.config;

import com.itheima.bean.Cat;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

//proxyBeanMethods,默认值true,使用CGLIB方式创建动态代理对象。false,输出对象内存地址
// 使用此注解保证此类内部创建的所有bean都是同一个对象
@Configuration(proxyBeanMethods = true)
public class SpringConfig33 {

    @Bean
    public Cat cat(){
        Cat cat = new Cat();
        return cat;
    }
}
package com.itheima.app;

import com.itheima.config.SpringConfig33;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App33 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig33.class);

        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        System.out.println("----------------");
        SpringConfig33 springConfig33 = context.getBean(SpringConfig33.class);
        System.out.println(springConfig33);
        System.out.println(springConfig33.cat());
        System.out.println(springConfig33.cat());
        System.out.println(springConfig33.cat());
    }
}

e09d370272b844248a5ed919096062be.png

保证自身类中内部bean的唯一性 

@ImportResource注解

package com.itheima.config;


import org.springframework.context.annotation.ImportResource;

//将原始xml配置文件中信息,迁移到注解配置类中使用。便于后期把原始项目的xml方式变更为注解方式开发
@ImportResource({"applicationContext1.xml","applicationContext12.xml"})
public class SpringConfig32 {

}

 方式4:@Import方式:

package com.itheima.bean;

public class Dog {
}
package com.itheima.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


public class DbConfig {

    @Bean
    public DruidDataSource dataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        return druidDataSource;
    }
}
package com.itheima.config;

import com.itheima.bean.Dog;
import org.springframework.context.annotation.Import;

//使用@Import导入bean直接使用类名.class即可,无需使用@Component等注解定义bean,便于spring解耦操作
@Import({Dog.class,DbConfig.class})
public class SpringConfig4 {


}

可以使用Import注入配置类,注入的配置类无需将自身类定义为bean,当做一个普通类即可

特点:使用import注入bean直接使用类名.class就可以把普通类加载为bean

 方式5:手工加载bean

package com.itheima.bean;

import org.springframework.stereotype.Component;

@Component("Tom")
public class Cat {

    private String name;

    public Cat() {
    }

    public Cat(String name) {
        this.name = name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                '}';
    }
}
package com.itheima.app;

import com.itheima.bean.Cat;
import com.itheima.config.SpringConfig4;
import com.itheima.config.SpringConfig5;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App5 {
    public static void main(String[] args) {
        //必须使用ApplicationContext接口,实现类AnnotationConfigApplicationContext才能手动加载bean
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig5.class);

        //spring容器初始化完毕后,手工加载bean
        //同时加载同一个bean,后加载会覆盖之前加载的bean
        context.registerBean("cat", Cat.class,"cat1");
        context.registerBean("cat", Cat.class,"cat2");
        context.registerBean("cat", Cat.class,"cat3");

        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

        System.out.println(context.getBean(Cat.class));
    }
}

fbcbd54c54454e65be997154eb24512f.png

  方式6:使用实现类ImportSelector

package com.itheima.bean;

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;


import java.util.Map;

public class MyImportSelector implements ImportSelector {

    //通过各种判定决定具体加载哪些bean
    //Metadata元数据
    public String[] selectImports(AnnotationMetadata metadata) {
        //hasAnnotation判断当前元数据类是否使用了指定注解,导入注解的全路径名
        boolean flag = metadata.hasAnnotation("org.springframework.context.annotation.Configuration");

        //获取元数据类中指定注解中的所有属性值
        //当前为查看@ComponentScan注解中的所有属性
        Map<String, Object> attributes = metadata.getAnnotationAttributes("org.springframework.context.annotation.ComponentScan");
        System.out.println("---------------------");
        System.out.println(attributes);
        System.out.println("---------------------");

        //对是否加载bean做出判断
        if (flag){
            return new String[]{
                    "com.itheima.bean.Cat"
            };
        }else {
            return new String[]{
                    "com.itheima.bean.Dog"
            };
        }
    }
}

元数据类: 

package com.itheima.config;

import com.itheima.bean.MyImportSelector;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

//通过导入ImportSelector接口的实现类加载bean
//ImportSelector导入在哪个位置当前位置就是元数据类
@Import(MyImportSelector.class)
@Configuration
@ComponentScan(basePackages = {"com.itheima.bean"})
public class SpringConfig6 {

}

1f1726a01b1d4f50839ef7f42f038da7.png

c623ed26ffd648c6b78b0e9c32935b40.png

   方式7:使用实现类ImportBeanDefinitionRegistrar

package com.itheima.bean;


import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata
            , BeanDefinitionRegistry registry) {

        //获取bean的字节码文件
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(Dog.class).getBeanDefinition();
        //使用bean名称生成器指定bean的名称
        //需要指定bean的名称和字节码文件
        registry.registerBeanDefinition("Spike",beanDefinition);
    }
}
package com.itheima.config;

import com.itheima.bean.MyRegistrar;
import org.springframework.context.annotation.Import;


@Import(MyRegistrar.class)
public class SpringConfig7 {

}

480e004b028b4417a405a9aae415f05c.png

ImportSelector和ImportBeanDefinitionRegistrar区别:

ImportSelector:元数据全路径名生成bean。

ImportBeanDefinitionRegistrar:使用BeanDefiniton指定定类的class文件和bean名称生成bean

   方式8:实现类BeanDefinitionRegistryPostProcessor

package com.itheima.bean.service.impl;

import com.itheima.bean.service.BookService;
import org.springframework.stereotype.Service;

@Service("BookService")
public class BookServiceImpl1 implements BookService {
    public void check() {
        System.out.println("book Service 1..");
    }
}

 BookService模拟了4个实现类,每个方法调用check都是都是输出book Service n...

如:BookServiceImpl1输出book Service 1..

       BookServiceImpl2输出book Service 2..

       ......

package com.itheima.bean;


import com.itheima.bean.service.impl.BookServiceImpl2;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyRegistrar2 implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata
            , BeanDefinitionRegistry registry) {

        //获取bean的字节码文件
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl2.class).getBeanDefinition();
        //使用bean名称生成器:指定bean的名称、bean的字节码文件
        registry.registerBeanDefinition("BookService",beanDefinition);
    }
}
package com.itheima.bean;

import com.itheima.bean.service.impl.BookServiceImpl3;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyRegistrar3 implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata
            , BeanDefinitionRegistry registry) {

        //获取bean的字节码文件
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl3.class).getBeanDefinition();
        //使用bean名称生成器:指定bean的名称、bean的字节码文件
        registry.registerBeanDefinition("BookService",beanDefinition);
    }
}
package com.itheima.bean;

import com.itheima.bean.service.impl.BookServiceImpl4;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;

public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        //获取bean的字节码文件
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl4.class).getBeanDefinition();
        //使用bean名称生成器:指定bean的名称、bean的字节码文件
        registry.registerBeanDefinition("BookService",beanDefinition);
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {

    }
}
package com.itheima.config;

import com.itheima.bean.MyPostProcessor;
import com.itheima.bean.MyRegistrar2;
import com.itheima.bean.MyRegistrar3;
import com.itheima.bean.service.impl.BookServiceImpl1;
import org.springframework.context.annotation.Import;


@Import({BookServiceImpl1.class,MyPostProcessor.class,MyRegistrar3.class,MyRegistrar2.class})
public class SpringConfig8 {

}

使用@import方式导入上面四种创建bean

package com.itheima.app;

import com.itheima.bean.service.BookService;
import com.itheima.config.SpringConfig8;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App8 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig8.class);

        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        
        BookService bookService = (BookService) context.getBean("BookService");
        bookService.check();
    }
}

通过4种不同的方式创建BookService的bean,并调用当中的同一个方法。

观察调用的结果

eb0010849b8b46019dcb36a9558e0dbc.png

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值