写点什么

京东面试,这个问题让我与 50 万擦肩而过,帮忙看看,mysql 下载教程 window10

用户头像
极客good
关注
发布于: 刚刚

:看着面试官,犹豫了 10 秒钟,说:不加 @Configuration 通过 @Bean 注解也可以注册 bean


面试官:你确定可以注册?


:嗯。。。。嗯。。。。嗯,我确定可以注册


面试官:那加不加到底有什么区别呢?


:好像没有什么区别啊


面试官:好像没区别。。。。先回去等通知吧!


结果可想而知,没戏了!


回去之后立即看 spring 的源码,终于搞清了这个问题,原来加不加 @Configuration 还是有相当大的区别的。


下面我们就来看看 @Configuration 注解到底是干什么的,加不加到底有什么区别,下次你们去面试的时候就可以给面试官吹吹了。


之前我们都是通过 xml 的方式定义 bean,里面会写很多 bean 元素,然后 spring 启动的时候,就会读取 bean xml 配置文件,然后解析这些配置,然后会将这些 bean 注册到 spring 容器中,供使用者使用。


jdk1.5 里面有了注解的功能,spring 也没闲着,觉得注解挺好用的,就将注解加了进来,让我们通过注解的方式来定义 bean,用起来能达到 xml 中定义 bean 一样的效果,并且更简洁一些,这里面需要用到的注解就有 @Configuration 注解和 @Bean 注解。


@Configuration 注解



用法

@Configuration 这个注解可以加在类上,让这个类的功能等同于一个 bean xml 配置文件,如下:


@Configuration


public?class?ConfigBean?{


}


上面代码类似于下面的 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-4.3.xsd">


</beans>


通过


AnnotationConfigApplicationContext 来加载 @Configuration 修饰的类,如下:


AnnotationConfigApplicationContext?context?=?new?AnnotationConfigApplicationContext(ConfigBean.class);


此时 ConfigBean 类中没有任何内容,相当于一个空的 xml 配置文件,此时我们要在 ConfigBean 类中注册 bean,那么我们就要用到 @Bean 注解了。

总结一下

@Configuration 使用步骤:


  1. 在类上使用 @Configuration 注解

  2. 通过 AnnotationConfigApplicationContext 容器来加 @Configuration 注解修饰的类


@Bean 注解



用法

这个注解类似于 bean xml 配置文件中的 bean 元素,用来在 spring 容器中注册一个 bean。


@Bean 注解用在方法上,表示通过方法来定义一个 bean,默认将方法名称作为 bean 名称,将方法返回值作为 bean 对象,注册到 spring 容器中。


如:


@Bean


public?User?user1()?{


return?new?User();


}


@Bean 注解还有很多属性,我们来看一下其源码:


@Target({ElementType.METHOD,?ElementType.ANNOTATION_TYPE})?//@1


@Retention(RetentionPolicy.RUNTIME)


@Documented


public?@interface?Bean?{


@AliasFor("name")


String[]?value()?default?{};


@AliasFor("value")


String[]?name()?default?{};


@Deprecated


Autowire?autowire()?default?Autowire.NO;


boolean?autowireCandidate()?default?true;


String?initMethod()?default?"";


String?destroyMethod()?default?AbstractBeanDefinition.INFER_METHOD;


}


@1:说明这个注解可以用在方法和注解类型上面。



每个参数含义:



value 和 name 是一样的,设置的时候,这 2 个参数只能选一个,原因是 @AliasFor 导致的



@AliasFor 这个注解不清楚的可以看这个文章:详解注解



value:字符串数组,第一个值作为 bean 的名称,其他值作为 bean 的别名



autowire:这个参数上面标注了 @Deprecated,表示已经过期了,不建议使用了



autowireCandidate:是否作为其他对象注入时候的


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


候选 bean,之前的文章中专门介绍过这个属性,不清楚的可以去看看:autowire-candidate 详解



initMethod:bean 初始化的方法,这个和生命周期有关,以后详解



destroyMethod:bean 销毁的方法,也是和生命周期相关的,以后详解

案例

User 类


package?com.javacode2018.lesson001.demo20;


public?class?User?{


}


Bean 配置类:ConfigBean


package?com.javacode2018.lesson001.demo20;


import?org.springframework.context.annotation.Bean;


import?org.springframework.context.annotation.Configuration;


@Configuration


public?class?ConfigBean?{


//bean 名称为方法默认值:user1


@Bean


public?User?user1()?{


return?new?User();


}


//bean 名称通过 value 指定了:user2Bean


@Bean("user2Bean")


public?User?user2()?{


return?new?User();


}


//bean 名称为:user3Bean,2 个别名:[user3BeanAlias1,user3BeanAlias2]


@Bean({"user3Bean",?"user3BeanAlias1",?"user3BeanAlias2"})


public?User?user3()?{


return?new?User();


}


}


上面通过 @Bean 注解定义了 3 个 bean,比较简单


来个测试类


package?com.javacode2018.lesson001.demo20;


import?org.junit.Test;


import?org.springframework.context.annotation.AnnotationConfigApplicationContext;


import?java.util.Arrays;


public?class?ConfigurationTest?{


@Test


public?void?test1()?{


AnnotationConfigApplicationContext?context?=?new?AnnotationConfigApplicationContext(ConfigBean.class);//@1


for?(String?beanName?:?context.getBeanDefinitionNames())?{


//别名


String[]?aliases?=?context.getAliases(beanName);


System.out.println(String.format("bean 名称:%s,别名:%s,bean 对象:%s",


beanName,


Arrays.asList(aliases),


context.getBean(beanName)));


}


}


}


@1:通过


AnnotationConfigApplicationContext 来加载配置类 ConfigBean,会将配置类中所有的 bean 注册到 spring 容器中



for 循环中输出了 bean 名称、别名、bean 对象


运行 test1 方法输出


bean 名称:org.springframework.context.annotation.internalConfigurationAnnotationProcessor,别名:[],bean 对象:org.springframework.context.annotation.ConfigurationClassPostProcessor@3bd82cf5


bean 名称:org.springframework.context.annotation.internalAutowiredAnnotationProcessor,别名:[],bean 对象:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@544fa968


bean 名称:org.springframework.context.annotation.internalCommonAnnotationProcessor,别名:[],bean 对象:org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@247bddad


bean 名称:org.springframework.context.event.internalEventListenerProcessor,别名:[],bean 对象:org.springframework.context.event.EventListenerMethodProcessor@d35dea7


bean 名称:org.springframework.context.event.internalEventListenerFactory,别名:[],bean 对象:org.springframework.context.event.DefaultEventListenerFactory@7770f470


bean 名称:configBean,别名:[],bean 对象:com.javacode2018.lesson001.demo20.ConfigBean



dde45976@5e5d171f


bean 名称:user1,别名:[],bean 对象:com.javacode2018.lesson001.demo20.User@24313fcc


bean 名称:user2Bean,别名:[],bean 对象:com.javacode2018.lesson001.demo20.User@7d20d0b


bean 名称:user3Bean,别名:[user3BeanAlias2,?user3BeanAlias1],bean 对象:com.javacode2018.lesson001.demo20.User@77f1baf5


上面的输出,我们主要关注与最后 4 行,前面的可以先忽略。



从输出中可以看出,有个名称为 configBean 的 bean,正是 ConfigBean 这个类型,可以得出,被 @Configuration 修饰的类,也被注册到 spring 容器中了



最后 3 行输出就是几个 User 的 bean 对象了。


上面的用法应该很多人都比较熟悉,下面的属于重点了。


去掉 @Configuration 会怎样?




我们来看一下没有 @Configuration 的时候,什么效果。


新建一个 ConfigBean1 类


内容和 ConfigBean 类一样,只是将 @Configuration 注解去掉了,如下:


public?class?ConfigBean1?{


//bean 名称为方法默认值:user1


@Bean


public?User?user1()?{


return?new?User();


}


//bean 名称通过 value 指定了:user2Bean


@Bean("user2Bean")


public?User?user2()?{


return?new?User();


}


//bean 名称为:user3Bean,2 个别名:[user3BeanAlias1,user3BeanAlias2]


@Bean({"user3Bean",?"user3BeanAlias1",?"user3BeanAlias2"})


public?User?user3()?{


return?new?User();


}


}


来个测试用例 test2


代码类似于 test1,给 spring 容器传递 ConfigBean1


@Test


public?void?test2()?{


AnnotationConfigApplicationContext?context?=?new?AnnotationConfigApplicationContext(ConfigBean1.class);


for?(String?beanName?:?context.getBeanDefinitionNames())?{


//别名


String[]?aliases?=?context.getAliases(beanName);


System.out.println(String.format("bean 名称:%s,别名:%s,bean 对象:%s",


beanName,


Arrays.asList(aliases),


context.getBean(beanName)));


}


}


运行输出


bean 名称:org.springframework.context.annotation.internalConfigurationAnnotationProcessor,别名:[],bean 对象:org.springframework.context.annotation.ConfigurationClassPostProcessor@333291e3


bean 名称:org.springframework.context.annotation.internalAutowiredAnnotationProcessor,别名:[],bean 对象:org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@479d31f3


bean 名称:org.springframework.context.annotation.internalCommonAnnotationProcessor,别名:[],bean 对象:org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@40ef3420


bean 名称:org.springframework.context.event.internalEventListenerProcessor,别名:[],bean 对象:org.springframework.context.event.EventListenerMethodProcessor@498d318c


bean 名称:org.springframework.context.event.internalEventListenerFactory,别名:[],bean 对象:org.springframework.context.event.DefaultEventListenerFactory@6e171cd7


bean 名称:configBean1,别名:[],bean 对象:com.javacode2018.lesson001.demo20.ConfigBean1@402bba4f


bean 名称:user1,别名:[],bean 对象:com.javacode2018.lesson001.demo20.User@795cd85e


bean 名称:user2Bean,别名:[],bean 对象:com.javacode2018.lesson001.demo20.User@59fd97a8


bean 名称:user3Bean,别名:[user3BeanAlias2,?user3BeanAlias1],bean 对象:com.javacode2018.lesson001.demo20.User@f5ac9e4


分析结果


我们将 2 个输出的最后 4 行拿来对比一下:


有 @Configuration 注解的


bean 名称:configBean,别名:[],bean 对象:com.javacode2018.lesson001.demo20.ConfigBean



dde45976@5e5d171f


bean 名称:user1,别名:[],bean 对象:com.javacode2018.lesson001.demo20.User@24313fcc


bean 名称:user2Bean,别名:[],bean 对象:com.javacode2018.lesson001.demo20.User@7d20d0b


bean 名称:user3Bean,别名:[user3BeanAlias2,?user3BeanAlias1],bean 对象:com.javacode2018.lesson001.demo20.User@77f1baf5

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
京东面试,这个问题让我与50万擦肩而过,帮忙看看,mysql下载教程window10