网站维护主要内容,app推广拉新渠道,idc新人如何做自己的网站,互联网网站开发html5Bean的获取方式
常见获取方式
虽然Spring为Bean对象的创建提供了多种实例化方式如由前期xml配置逐步演化成注解配置,但本质都是通过反射机制加载类名后创建对象,最后交给Spring管控
Spring还开放出了若干种可编程控制的bean的初始化方式#xff0c;通过分支语句由固定的加载…Bean的获取方式
常见获取方式
虽然Spring为Bean对象的创建提供了多种实例化方式如由前期xml配置逐步演化成注解配置,但本质都是通过反射机制加载类名后创建对象,最后交给Spring管控
Spring还开放出了若干种可编程控制的bean的初始化方式通过分支语句由固定的加载bean转成了可以选择bean是否加载或者选择加载哪一种bean
方式描述xml bean/在spring配置文件中直接配置类全路径然后自动调用该类的无参数构造方法来实例化Beanxml:context注解(Component4个Bean)配置类扫描注解 (Component4个Bean)Bean定义FactoryBean接口,ImportResource,Configuration注解的proxyBeanMethods属性Import导入Bean的类,这个类也可以是配置类指定加载某一个类作为spring管控的bean被加载的类中Bean相关的定义也会被一同加载AnnotationConfigApplicationContext调用register方法Import导入ImportSelector接口选择性的加载BeanImport导入ImportBeanDefinitionRegistrar接口选择性的加载Bean,并初始化Bean的相关属性Import导入BeanDefinitionRegistryPostProcessor接口对注册的Bean做最后统一处理
XML声明Bean
通过无参构造方法实例化: 在spring.xml配置文件中直接配置类的全路径,Spring会自动调用该类的无参数构造方法实例化Bean并交给容器管理
Bean的名称可以通过bean标签的id属性指定,默认名称是全类名#有序数字
XML声明Bean方式的优缺点
优点: 通过一个配置文件可以查阅当前Spring环境中定义了多少个或者说多少种bean,既可以配置自定义的Bean也可以配置第三方声明的Bean缺点: 需要将Spring管控的Bean全部写在spring.xml文件中对于程序员来说非常不友好
public class User {public User() {System.out.println(User类的无参数构造方法执行);}
}?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd!--指定创建Bean的名称--bean iduserBean classcom.powernode.spring6.bean.User/!--默认名称是全类名#有序数字--bean classcom.powernode.spring6.bean.User/
/beans简单(静态)工厂模式实例化
第一步定义一个BeanVip
public class Vip {
}第二步编写工厂类VipFactory并定义静态方法负责创建Bean,同时也可以对创建的Bean进行加工处理
public class VipFactory {public static Vip get(){// 可以对Bean加工处理return new Vip();}
}第三步在spring.xml配置文件中使用factory-method属性告诉Spring框架调用哪个静态工厂类的哪个静态方法获取Bean
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd!--配置静态工厂类和静态方法--bean idvipBean classcom.powernode.spring6.bean.VipFactory factory-methodget/
/beans第四步: 根据Id从容器中获取Bean,此时容器返回的Bean是通过调用静态工厂的静态方法得到的
Test
public void testSimpleFactory(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring.xml);Vip vip applicationContext.getBean(vipBean, Vip.class);//com.powernode.spring6.bean.Vip79e2c065System.out.println(vip);
}工厂方法模式实例化
第一步: 定义一个具体产品类
public class Order {
}第二步: 定义一个具体工厂类同时定义创建Bean的实例方法
public class OrderFactory {public Order get(){// 可以对Bean加工处理return new Order();}
}第三步: 在spring.xml配置文件中先注册工厂Bean,使用factory-bean和factory-method属性告诉Spring框架,调用哪个工厂对象的哪个实例方法获取Bean
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd!--先注册工厂Bean--bean idorderFactory classcom.powernode.spring6.bean.OrderFactory/!--告诉Spring框架调用哪个工厂对象的哪个实例方法获取Bean--bean idorderBean factory-beanorderFactory factory-methodget/
/beans第四步: 根据Id从容器中获取Bean,此时获取的Bean对象是通过调用工厂Bean的实例方法得到的
Test
public void testSelfFactoryBean(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring.xml);Order orderBean applicationContext.getBean(orderBean, Order.class);//com.powernode.spring6.bean.Order35cabb2aSystem.out.println(orderBean);
}FactoryBean接口实例化
BeanFactory和FactoryBean
在Spring中Bean可以分为普通Bean和工厂Bean两类,工厂Bean也是一种特殊的Bean,只不过它可以辅助Spring实例化其它的Bean对象同时对Bean进行加工处理
BeanFactory(Bean工厂)是Spring容器的超级接口专门负责创建Bean对象, ApplicationContext只是BeanFactory的一个子接口 BeanFactory beanFactory new ClassPathXmlApplicationContext(spring.xml);Object vipBean beanFactory.getBean(vipBean);System.out.println(vipBean);Spring提供了一个FactoryBean创建Bean的类型接口专门负责创建Bean,实现该接口的类被称为工厂Bean即可以协助框架创建Bean对象同时对Bean加工处理 如果工厂类实现了FactoryBean接口的getObject()方法,可以不指定factory-bean和factory-method属性,直接通过工厂Bean就可以获取其创建的Bean factory-bean属性会自动指向实现了FactoryBean接口的工厂Beanfactory-method属性会自动指向工厂Bean的getObject()方法
方法名功能getObjectType()Spring会自动调用这个方法来确认创建对象的字节码对象getObject()Spring自己会调用这个方法返回创建的Bean并交给容器管理,在返回Bean前可以进行其他的加工处理isSingleton()指定工厂Bean创建的Bean是否是单例的 , false表示非单例 ,true(默认值)表示单例
基于XML实例化
第一步: 定义一个具体产品类Person
public class Person {
}第二步: 编写一个工厂类PersonFactoryBean实现FactoryBean接口的getObject方法,接口泛型就是要创建Bean的类型
public class PersonFactoryBean implements FactoryBeanPerson {Overridepublic Person getObject() throws Exception {// 对Bean创建前加工处理return new Person();// 对Bean创建后加工处理}Overridepublic Class? getObjectType() {return null;}// 这个方法在接口中有默认实现所有可以不用实现Overridepublic boolean isSingleton() {return true;}
}第三步: 在spring.xml配置文件注册实现了FactoryBean接口的工厂Bean
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd!--注册一个特殊的工厂Bean,可以对普通的Bean进行加工处理并返回--bean idpersonBean classcom.powernode.spring6.bean.PersonFactoryBean/
/beans第四步: 根据Id从容器中获取工厂Bean,此时容器返回的是该工厂Bean创建的Bean对象(默认是单例的)
Test
public void testFactoryBean(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring.xml);Person personBean applicationContext.getBean(personBean, Person.class);//com.powernode.spring6.bean.Person79e2c065System.out.println(personBean);// 默认工厂Bean创建的Bean是单例的Person personBean2 applicationContext.getBean(personBean, Person.class);//com.powernode.spring6.bean.Person79e2c065System.out.println(personBean2);
}基于注解实例化
FactoryBean接口也可以用于声明Bean, 实现了FactoryBean接口的类造出来的对象不是当前类的对象,而是FactoryBean接口泛型指定类型的对象
在FactoryBean接口的getObject方法中完成对象的加工处理相对于在对象的构造方法中加工处理的优点
在对象的构造方法中加工处理: 如果当前构造方法的初始化动作并不能满足你的需要,就需要重写一个构造方法在FactoryBean接口的getObject方法中加工处理: 类是一个抽象后剥离的特别干净的模型, 根据情况不同在对象初始化前后设置不同的初始化动作
public class DogFactoryBean implements FactoryBeanDog {Overridepublic Dog getObject() throws Exception {// 对象创建前做的事情Dog d new Dog();// 对象创建后做的事情return d;}Overridepublic Class? getObjectType() {return Dog.class;}Overridepublic boolean isSingleton() {return true;}
}使用Bean的形式创建FactoryBean接口实现类DogFactoryBean的泛型对象,FactoryBean接口的实现类并不会被加载到容器
ComponentScan({com.itheima.bean,com.itheima.config})
public class SpringConfig3 {Beanpublic DogFactoryBean dog(){// 返回的是Dog类型的对象return new DogFactoryBean();}
}注入自定义类型Date
需求: 为Student对象注入一个Data类型的日期作为生日
public class Student {private Date birth;public void setBirth(Date birth) {this.birth birth;}Overridepublic String toString() {return Student{ birth birth };}
}java.util.Date在Spring中被当做简单类型,所以在注入属性值的时候可以直接使用value属性或value标签来完成
对Date类型属性赋值的时要求日期字符串的格式必须是指定格式Mon Oct 10 14:30:26 CST 2022, 如果是其他格式是不会被识别的
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd!--调用Data的无参构造方法获取系统当前时间--bean idnowTime classjava.util.Date/bean idstudent classcom.powernode.spring6.bean.Student!--把日期类型当做简单类型,要求日期格式必须是指定的才能为Date类型的属性赋值--property namebirth valueMon Oct 10 14:30:26 CST 2022/!--把日期类型当做非简单类型,默认格式的日期无法为Date类型的属性赋值--property namebirth refnowTime//bean
/beans 第一步: 编写DateFactoryBean实现FactoryBeanDate接口, 对java.util.Date类型的普通Bean加工并交给容器管理
public class DateFactoryBean implements FactoryBeanDate {// 定义Date属性接收日期字符串private String date;// 通过构造方法给Date属性赋值public DateFactoryBean(String date) {this.date date;}// 对Date类型的Bean加工处理并交给容器管理Overridepublic Date getObject() throws Exception {SimpleDateFormat sdf new SimpleDateFormat(yyyy-MM-dd);return sdf.parse(this.date);}Overridepublic Class? getObjectType() {return null;}
}第二步: 编写spring.xml的配置文件注册DateFactoryBean,然后赋值给Student对象Date类型的属性(注入的是java.util.Date类型的Bean)
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd!--通过DateFactoryBean对java.util.Date类型的Bean做加工处理,最后返回给容器的也是java.util.Date类型的Bean--bean iddateBean classcom.powernode.spring6.bean.DateFactoryBeanconstructor-arg namedate value1999-10-11//beanbean idstudentBean classcom.powernode.spring6.bean.Student!--这里引用的是加工处理后的java.util.Date类型的普通bean--property namebirth refdateBean//bean
/beans第三步: 根据Id从容器中获取Student类型的Bean,查看其Date类型的属性值
Test
public void testDate(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring.xml);Student studentBean applicationContext.getBean(studentBean, Student.class);//Student{birthMon Oct 11 00:00:00 CST 1999}System.out.println(studentBean);
}使用注解获取
注解的存在主要是为了简化XML的配置, 只要使用了Spring提供的注解就要使用包扫描机制,这样Spring才会根据配置的注解创建Bean并交给容器管理
使用注解一般加入的是自己写的组件 , 使用bean标签配置加入的是别人的写的组件 , 开发中常用注解和bean配置相结合的方式
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsdcontext:component-scan base-packagecom.powernode.spring6.bean4/
/beans标识类的四个注解
无论使用标识Bean的四个注解和还是使用XML配置的方式,最终注册到容器中组件的默认行为都是一样的,组件都有Id和默认作用域
如果同时使用了其他方式注册Bean,那么这四个注解只会起到指定Bean名称的作用四个注解都只有一个value属性用来指定Bean的Id,Id默认是组件的简单类名首字母小写后得到的字符串,作用域默认是单例的
Spring无法识别到一个组件到底是不是它所标记的类型(注解只能起到标识作用),即使将Respository注解用在一个表述层控制器组件上面也不会产生任何错误
Respository、Service、Controller这几个注解仅仅是为了让开发人员自己明确当前的组件扮演的角色,增强程序的可读性
注解名功能Repository推荐标识受Spring IOC容器管理的持久化层组件Service推荐标识受Spring IOC容器管理的业务逻辑层组件Controller推荐标识受Spring IOC容器管理的表述层控制器组件Component推荐标识受Spring IOC容器管理的普通组件(不属于以上几层的组件)Scope指定放入容器的组件是多实例的还是单实例的 , 默认是单实例的 , prototype表示指定创建的Bean是多实例的
第一步: 在类上使用标识Bean的注解
Component(userBean)
public class User {
}第二步: 在spring.xml配置文件中使用context:component-scan标签扫描指定包中加了注解的组件,这样框架会创建对应的Bean对象同时交给IoC容器管理
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd!--告诉Spring框架要扫描哪些包中的类--context:component-scan base-packagecom.powernode.spring6.bean /context:component-scan
/beans第三步: 根据Id从容器中获取对应的Bean
public class AnnotationTest {Testpublic void testBean(){ApplicationContext applicationContext new ClassPathXmlApplicationContext(spring.xml);User userBean applicationContext.getBean(userBean, User.class);System.out.println(userBean);}
}Bean注解
Bean注解可以将它标识方法返回的对象注册成Bean交给IoC容器管理,默认方法的名称就是Bean的Id(注解的name属性可以单独指定Bean的Id)
注解方法一定要在Configuration(常用)/Component修饰的类中,Spring只有先扫描到类然后才能将类中Bean注解标识方法的返回对象交给容器管理Spring还会自动根据方法的形参的类型去容器中找对应的bean实现自动注入,如果找到了多个bean会以方法的形参名作为Id继续匹配,不需要使用自动注入注解
第一步: 定义一个配置类,使用ComponentScan注解代替包扫描的动作,在配置类中使用Bean注解标识方法
如果手动指定要加载的配置类那么Configuration/Component注解可以省略,如果是通过包扫描的方式加载配置类那么就不能省略注解
// Component
// Configuration
ComponentScan({com.bean})
public class DbConfig {Beanpublic DruidDataSource dataSource(){DruidDataSource ds new DruidDataSource();return ds;}
}第二步: 使用AnnotationConfigApplicationContext加载配置类的字节码对象创建容器对象,配置类也会注册成Bean由容器管理(Id默认是简类名首字母小写)
Test
public void testNoXml(){//不再通过创建ClassPathXmlApplicationContext()获取容器对象ApplicationContext applicationContext new AnnotationConfigApplicationContext(SpringConfiguration.class);DruidDataSource dataSource applicationContext.getBean(dataSource, DruidDataSource.class);
} Configuration注解
Configuration注解的proxyBeanMethods属性可以指定类中Bean标识的方法创建的对象是否为单实例
true(默认值): 此时会创建配置类的代理对象,如果调用配置类中使用Bean注解标识的方法,获取的是容器中第一次加载配置类时创建的那个Bean对象(单例)false:此时会创建配置类的普通对象,每调用一次配置类中使用Bean注解标识的方法获取的都是一个新创建的对象(多实例)
第一步: 创建一个配置类并使用Bean标识方法
Configuration(proxyBeanMethods true)
public class SpringConfig {Beanpublic Cat cat(){return new Cat();}// 在配置类中多次调用Cat()方法得到的是同一个对象Cat();Cat();
}第二步: 获取配置类的代理对象并多次调用配置类中使用了Bean标识方法,最终得到的都是同一个对象(Spring Boot源码和MQ中都应用了此特性)
public class App33 {public static void main(String[] args) {// 此时创建容器时获取的是配置类的代理对象ApplicationContext ctx new AnnotationConfigApplicationContext(SpringConfig.class);String[] names ctx.getBeanDefinitionNames();for (String name : names) {System.out.println(name);}System.out.println(-------------------------);SpringConfig springConfig ctx.getBean(springConfig, SpringConfig.class);System.out.println(springConfig.cat());System.out.println(springConfig.cat());System.out.println(springConfig.cat());}
}ImportResource注解
由于早起开发的系统大部分都是采用XML的形式配置Bean而现在的企业级开发基本采用注解形式,所以就需要两种模式同时使用
Spring提供了一个ImportResource注解在配置类上直接写上要被融合的XML配置文件名(类路径下)即可(注意导入的Bean可能发生冲突)
加载的多个XML文件中的Bean冲突时后加载的Bean留下,加载的xml中的Bean和当前采用注解形式配置的Bean冲突时,以XML方式配置的Bean留下
ImportResource(applicationContext1.xml)
public class SpringConfig {
}?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd!--声明自己开发的bean--bean idcat classCat/!--声明第三方开发的bean--bean iddataSource classcom.alibaba.druid.pool.DruidDataSource/bean classcom.alibaba.druid.pool.DruidDataSource/
/beansImport注解
相对于Bean注解通过Import注解加载第三方Bean更加简便,只需要在注解的参数中写上加载的类对应的Class对象即可(Bean的名称默认是类的全类名)
优点: 无侵入编程,可以降低源代码与Spring技术的耦合度,对当前类的形式没有影响缺点: 扫描的时候不仅可以加载到你要的东西还有可能加载到各种各样的乱七八糟的东西
Import(Dog.class)
public class SpringConfig {
}使用Import注解还可以加载配置类(该配置类不需要使用Configuration/Component注解声明),配置类里面使用了Bean标识方法的返回对象也会注册成Bean
Import(DbConfig.class)
public class SpringConfig {
}手动向容器中注册Bean
一般加载Bean的方式都是在容器启动阶段完成Bean的加载,但有时候也会在容器初始化完成后向容器中注册Bean
AnnotationConfigApplicationContext接口特有的方法
方法名功能register(Class)向容器注册一个Bean不指定名称(默认名称是类名的首字母小写)registerBean(Id,Class,构造方法参数可变)向容器注册一个Bean并指定名称
如果注册的Bean的Id相同新添加的Bean就会覆盖原有的Bean(容器的底层类似Map集合),这样可以保证我们自己手动添加的配置覆盖原有的配置
public class App {public static void main(String[] args) {AnnotationConfigApplicationContext ctx new AnnotationConfigApplicationContext(SpringConfig.class);// 上下文容器对象已经初始化完毕后手工加载Beanctx.register(Mouse.class);ctx.registerBean(tom, Cat.class,0);ctx.registerBean(tom, Cat.class,1);// 新添加的Bean会覆盖原有的BeanSystem.out.println(ctx.getBean(Cat.class));}
}实现接口
ImportSelector
编写一个类重写ImportSelector接口的selectImports方法,返回一个String类型的数组,数组元素就是要注册Bean的全类名(也是注册Bean的名称)
AnnotationMetadata是元数据即Import注解修饰的类如SpringConfig,通过元数据提供的方法我们可以做一些判断或者获取一些信息
方法名功能String getClassName()获取元数据的简类名boolean hasAnnotation(“”)判断元数据上是否有某个注解Map String,Object getAnnotationAttributes(“”)获取元数据上某个注解的所有属性
Configuration
//ComponentScan(basePackages com.itheima)
Import(MyImportSelector.class)
public class SpringConfig {
}public class MyImportSelector implements ImportSelector {Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {// 获取ComponentScan注解的属性集合,判断注解是是否有某个属性MapString, Object attributes metadata.getAnnotationAttributes(org.springframework.context.annotation.ComponentScan);// 根据各种条件判定是否装载指定的Bean,如判断元数据上是否有Configuration注解boolean flag importingClassMetadata.hasAnnotation(org.springframework.context.annotation.Configuration);if(flag){return new String[]{com.itheima.bean.Dog};}return new String[]{com.itheima.bean.Cat};}
} ImportBeanDefinitionRegistrar
编写一个类重写ImportBeanDefinitionRegistrar接口的registerBeanDefinitions方法,该方法额外提供了一个参数BeanDefinition
BeanDefinition对象可以设置Bean初始化时的相关属性(如名称或是否单例),通过类的Class对象可以获得其对应的BeanDefinition对象(一个Bean对应一个)
Import(MyRegistrar.class)
public class SpringConfig {
}public class MyRegistrar implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {// 使用元数据判定是否加载Bean.....// 通过Bean的Class对象获得其对应的BeanDefinition对象BeanDefinition beanDefinition BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl.class).getBeanDefinition();// 使用BeanDefinitionRegistry对象设置其对应Bean初始化时的名称registry.registerBeanDefinition(bookService,beanDefinition);}
}BeanDefinitionRegistryPostProcessor
如果使用不同方式加载了同种类型的Bean并且名称也相同,那么此时我们无法确定最后是使用的哪种方式向容器中注册的Bean(具体取决于导入Bean的顺序和方式)
重写BeanDefinitionRegistryPostProcessor接口的postProcessBeanDefinitionRegistry方法,实现对容器中Bean的最终裁定即之前的配置都会被覆盖
// 直接导入
Service(bookService)
public class BookServiceImpl1 implements BookSerivce {Overridepublic void check() {System.out.println(book service 1..);}
}
// 使用MyRegistrar注册
public class BookServiceImpl2 implements BookSerivce {Overridepublic void check() {System.out.println(book service 2....);}
}
// 使用MyRegistrar2注册
public class BookServiceImpl3 implements BookSerivce {Overridepublic void check() {System.out.println(book service 3....);}
}
// 使用MyPostProcessor注册
public class BookServiceImpl4 implements BookSerivce {Overridepublic void check() {System.out.println(book service 4....);}
}public class MyRegistrar implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {BeanDefinition beanDefinition BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl2.class).getBeanDefinition();registry.registerBeanDefinition(bookService,beanDefinition);}
}
public class MyRegistrar2 implements ImportBeanDefinitionRegistrar {Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {//1.使用元数据去做判定BeanDefinition beanDefinition BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl3.class).getBeanDefinition();registry.registerBeanDefinition(bookService,beanDefinition);}
}public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {Overridepublic void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {// 通过BeanDefinition的注册器注册实名BeanBeanDefinition beanDefinition BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl2.class).getBeanDefinition();// 在postProcessBeanDefinitionRegistry方法中注册Bean的优先级最高registry.registerBeanDefinition(bookService,beanDefinition);}
}// 使用import的方式导入BookService1,使用MyPostProcessor的方式导入BookService2,但它们的名称都为bookService
// 使用MyRegistrar注册Bean的优先级高会被留下,如果是相同的MyRegistrar与配置顺序有关,后面的覆盖前面的
// 使用MyPostProcessor.class注册Bean的优先级最高且与配置顺序无关,无论前面怎么配置都会覆盖
Import({BookServiceImpl.class,MyRegistrar.class,MyRegistrar2,MyPostProcessor.class})
public class SpringConfig {
}