这三种注解和xml形式的关系:@configuration = <beans></beans>@component =<bean></bean>放在类上@bean = <bean></bean> 放在方法上简要概述:Configuration和Component都是注解在类上的,Configuration类中的方法成员变量是@Value注解,方法上的注解是@Bean ,使用cglib 动态代理 标记的是 同一个对象 ; Component类中的方法和成员变量没有任何限制,由于相当于new所以每次取的不一定是同一个对象。 疑问由来首先看一下Spring官方文档是怎么说的: The @Bean methods in a Spring component are processed differently than their counterparts inside a Spring @Configuration class. The difference is that @Component classes are not enhanced with CGLIB to intercept the invocation of methods and fields. CGLIB proxying is the means by which invoking methods or fields within @Bean methods in @Configuration classes creates bean metadata references to collaborating objects; such methods are not invoked with normal Java semantics but rather go through the container in order to provide the usual lifecycle management and proxying of Spring beans even when referring to other beans via programmatic calls to @Bean methods. In contrast, invoking a method or field in an @Bean method within a plain @Component class has standard Java semantics, with no special CGLIB processing or other constraints applying. 在Component中(@Component标注的类,包括@Service,@Repository, @Controller)使用@Bean注解和在@Configuration中使用是不同的。在@Component类中使用方法或字段时不会使用CGLIB增强(及不使用代理类:调用任何方法,使用任何变量,拿到的是原始对象,后面会有例子解释)。而在@Configuration类中使用方法或字段时则使用CGLIB创造协作对象(及使用代理:拿到的是代理对象);当调用@Bean注解的方法时它不是普通的Java语义,而是从容器中拿到由Spring生命周期管理、被Spring代理甚至依赖于其他Bean的对象引用。在@Component中调用@Bean注解的方法和字段则是普通的Java语义,不经过CGLIB处理。 不知道上面写的是不是很拗口,可能还是不好理解,来个示例吧。 概念和示例首先介绍下Spring中Bean的生命周期,后面好解释运行结果。很熟悉的请跳过,由于我刚读Spring的手册,记录下加深印象。 Spring中Bean生命周期Bean简单来说就是Spring管理的对象,最常用的应该是Scope=Singleton的Bean。 一个最简单Singleton Bean它在Spring中的创建过程大致是,Singleton Bean完成这些在容器启动时:读取类定义 -> 调用构造函数实例化 -> 填充属性值 -> 初始化 消亡过程 ,一般是在容器关闭时: 销毁(析构前处理) -> 后面的事就不太清楚了,应该是Spring断开引用然后交由Java虚拟机自己处理。 不同Scope的Bean生命周期大致一样,完成的时机不同,例如prototype在使用时才做实例化之后的动作。 生命周期接口示例1.首先写一个Bean的配置类,在singleton的MyService中注入prototype的MyMode类。这里使用接口为了能自由选择JDK动态代理或CGLIB Mode接口
Service实现
上面的MyMode Bean使用了三个接口: ①注解@Bean的属性initMethod, destroyMethod ②接口InitializingBean, DisposableBean ③注解@PostConstruct,@PreDestroy 都作用于同样的两个过程——初始化阶段和销毁阶段 2、BeanPostProcessor
实现了BeanPostProcessor接口,该接口作用于Bean初始化前后 3、InstantiationAwareBeanPostProcessor
继承自一个抽象类,主要实现的还是InstantiationAwareBeanPostProcessor接口的方法,该接口作用于实例化阶段,完成实例化,属性描述修改以及实例化后处理逻辑 4、以下是Spring Boot的启动类,以及一个简单的Web Controller
5、启动应用,调用Controller打印结果: The Mode Bean injected in different Bean is the same object, class type is com.sun.proxy.$Proxy47 InstantiationBeanPostProcessor postProcessBeforeInstantiation called MyMode constructor call InstantiationBeanPostProcessor postProcessAfterInstantiation called InstantiationBeanPostProcessor postProcessPropertyValues called BeanPostProcessor postProcessBeforeInitialization called Mode @PostConstruct anno init called Mode afterPropertiesSet called Mode @Bean anno Init called BeanPostProcessor postProcessAfterInitialization called MyMode print called 1 MyMode constructor call InstantiationBeanPostProcessor postProcessAfterInstantiation called InstantiationBeanPostProcessor postProcessPropertyValues called BeanPostProcessor postProcessBeforeInitialization called Mode @PostConstruct anno init called Mode afterPropertiesSet called Mode @Bean anno Init called BeanPostProcessor postProcessAfterInitialization called MyMode print called 2 MyMode constructor call InstantiationBeanPostProcessor postProcessAfterInstantiation called InstantiationBeanPostProcessor postProcessPropertyValues called BeanPostProcessor postProcessBeforeInitialization called Mode @PostConstruct anno init called Mode afterPropertiesSet called Mode @Bean anno Init called BeanPostProcessor postProcessAfterInitialization called MyMode print called 3 由于MyMode是prototype的,每次调用不同实例,生命周期接口调用顺序应该是: postProcessBeforeInstantiation->constructor->postProcessAfterInstantiation->postProcessPropertyValues ->postProcessBeforeInitialization->( @PostConstruct->afterPropertiesSet->@Bean init)->postProcessAfterInitialization ->( @PostDestroy>destroy->@Bean destroy) postProcessBeforeInstantiation只调用一次,说明某个类不管在Spring中有几个相应的对象,其原始实例只有一个。 但是为什么销毁阶段的函数没调用,因为Spring文档就这样写的,prototype资源当做普通对象自己代码中释放就好。暂时将MyMode的Scope改为WebApplicationContext.SCOPE_REQUEST。输出如下: The Mode Bean injected in different Bean is the same object, class type is com.sun.proxy.$Proxy47 InstantiationBeanPostProcessor postProcessBeforeInstantiation called MyMode constructor call InstantiationBeanPostProcessor postProcessAfterInstantiation called InstantiationBeanPostProcessor postProcessPropertyValues called BeanPostProcessor postProcessBeforeInitialization called Mode @PostConstruct anno init called Mode afterPropertiesSet called Mode @Bean anno Init called BeanPostProcessor postProcessAfterInitialization called MyMode print called 1 MyMode print called 1 MyMode print called 1 Mode @PreDestroy anno destory called Mode destroy called Mode @Bean anno destory called @Configuration与@Component上面例子不仅描述了Spring生命周期,注意TestBeanConfigration中那句new MyService(myMode()) 它是调用本类中的方法myMode(),当Scope=prototype时,根据上面第二次print的结果,实际上得到的却是拥有Spring生命周期Bean。 Spring官方文档所要表达的就是这个。 接下来试试TestBeanConfigration的@Configuration改为@Component,MyMode的Scope仍然是prototype。看看结果: 在启动时打印了一次:MyMode constructor call 调用Controller时: The Mode Bean injected in different Bean is different object. and they are different type : com.sun.proxy.$Proxy46,com.bean.MyMode InstantiationBeanPostProcessor postProcessBeforeInstantiation called MyMode constructor call InstantiationBeanPostProcessor postProcessAfterInstantiation called InstantiationBeanPostProcessor postProcessPropertyValues called BeanPostProcessor postProcessBeforeInitialization called Mode @PostConstruct anno init called Mode afterPropertiesSet called Mode @Bean anno Init called BeanPostProcessor postProcessAfterInitialization called MyMode print called 2 MyMode print called 1 MyMode constructor call InstantiationBeanPostProcessor postProcessAfterInstantiation called InstantiationBeanPostProcessor postProcessPropertyValues called BeanPostProcessor postProcessBeforeInitialization called Mode @PostConstruct anno init called Mode afterPropertiesSet called Mode @Bean anno Init called BeanPostProcessor postProcessAfterInitialization called MyMode print called 3 由以上结果可以看出使用@Component时,TestBeanConfigration调用本类中的方法myMode(),立马返回一个原始的MyMode对象,该对象就是简单的Java对象。 |
|
来自: windxn > 《Java技术指南》