前言
@Configuation是spring最常见的注解之一,很多人都很熟悉。说起这个注解的作用,大家一定会说,当类上有@Configuration的时候,可以在这个类中使用@Bean注解向spring容器中注册bean;如果没有@Configuration的时候,就无法注册Bean。事实真的是这样吗?
不使用@Configurtion
我们先看看传统注册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 id="qiaoyingzi" class="beans.vo.Student"> <property name="id" value="10086">property> <property name="age" value="18">property> <property name="name" value="乔英子">property> <property name="city" ref="beijing">property> bean> <bean id="fangyifan" class="beans.vo.Student"> <property name="id" value="10087">property> <property name="age" value="18">property> <property name="name" value="方一凡">property> <property name="city" ref="beijing">property> bean> <bean id="beijing" class="beans.vo.City"> <property name="id" value="110000">property> <property name="name" value="北京">property> bean>beans>
public class ConfigurationTest { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); Student qiaoyingzi = (Student) ac.getBean("qiaoyingzi"); Student fangyifan = (Student) ac.getBean("fangyifan"); System.out.println(qiaoyingzi); System.out.println(fangyifan); }}
输出结果
Connected to the target VM, address: '127.0.0.1:59054', transport: 'socket'beans.vo.Student@367ffa75beans.vo.Student@49438269Disconnected from the target VM, address: '127.0.0.1:59054', transport: 'socket'Process finished with exit code 0
我们用xml向bean容器注册了三个Bean,一个是学生类的对象"乔英子",一个是学生类的对象"方一凡",一个是城市类的对象"北京",乔英子和方一凡都有个依赖对象"北京"。
使用@Bean,不用@Configuration
public class StudentConfig { @Bean public City beijing(){ System.out.println("城市类对象被创建"); return new City(110000,"beijing"); } @Bean public Student qiaoyingzi(){ return new Student("10086","乔英子",18,beijing()); } @Bean public Student fangyifan(){ return new Student("10087","方一凡",18,beijing()); }}
public class ConfigurationTest { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(StudentConfig.class); ctx.refresh(); StudentConfig stuConfig=(StudentConfig) ctx.getBean("studentConfig"); Student qiaoyingzi= (Student)ctx.getBean("qiaoyingzi"); Student fangyifan= (Student)ctx.getBean("fangyifan"); System.out.println(stuConfig); System.out.println(qiaoyingzi); System.out.println(fangyifan); }}
输出结果
Connected to the target VM, address: '127.0.0.1:58487', transport: 'socket'城市类对象被创建城市类对象被创建城市类对象被创建beans.annotation.configuration.StudentConfig@4135c3bbeans.vo.Student@6302bbb1beans.vo.Student@31304f14Disconnected from the target VM, address: '127.0.0.1:58487', transport: 'socket'
我们没有加@Configuration同样向spring容器注册了Bean,配置类对象,学生类对象和城市类对象都被注入,其中城市类的对象被创建了三次
加上@Configuration和@Bean
我们只在StudentConfig上加上 @Configuration注解,再看输出结果
Connected to the target VM, address: '127.0.0.1:58499', transport: 'socket'城市类对象被创建beans.annotation.configuration.StudentConfig$$EnhancerBySpringCGLIB$$4fa8418e@740cae06beans.vo.Student@26d9b808beans.vo.Student@f78a47eDisconnected from the target VM, address: '127.0.0.1:58499', transport: 'socket'
乍一看没啥区别,其实我们可以发现,虽然两个学生类对象都有依赖对象"北京",但是城市对象只创建了一次,并且我们的配置类Bean StudentConfig打印信息多了"$EnhancerBySpringCGLIB$"这么一串东西。说明spring容器会用cglib为@Configuration修饰的类创建代理对象,被@Bean修饰的方法会全部被拦截,并且只执行一次。
总结:
不管@Bean所在的类是否有@Configuration注解,都可以将@Bean修饰的方法注册到spring容器
@Configuration注解修饰的类,spring会通过cglib产生一个代理对象,并且拦截@Bean修饰的方法,可以确保一些bean是单例(总结参考路人甲java)
本文链接:https://my.lmcjl.com/post/4517.html
4 评论