spring bean 注解怎么使用注解在初始化bean的时候init-method指定的方法

随笔 - 1082&
文章 - 7&评论 - 131&trackbacks - 0
随着spring注解的引入,越来越多的开发者开始使用注解,这篇文章将对注解的机制进行串联式的讲解,不求深入透彻,但求串起spring beans注解的珍珠,展示给大家。
1. spring beans常用的注解:
& public @interface Autowired:可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作。
Marks a constructor, field, setter method or config method as to be autowired by Spring's dependency injection facilities.
Only one constructor (at max) of any given bean class may carry this annotation, indicating the constructor to autowire when used as a Spring bean. Such a constructor does not have to be public.
Fields are injected right after construction of a bean, before any config methods are invoked. Such a config field does not have to be public.
Config methods may have an arbitrary name and any each of those arguments will be autowired with a matching bean in the Spring container. Bean property setter methods are effectively just a special case of such a general config method. Such config methods do not have to be public.
In the case of multiple argument methods, the 'required' parameter is applicable for all arguments.
In case of a Collection or Map dependency type, the container will autowire all beans matching the declared value type. In case of a Map, the keys must be declared as type String and will be resolved to the corresponding bean names.
Note that actual injection is performed through a BeanPostProcessor which in turn means that you cannot use @Autowired to inject references into BeanPostProcessor or BeanFactoryPostProcessor types. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).
& public @interface Configurable&@Configurable&注解中的autowire属性就可以让Spring来自动装配了:&@Configurable(autowire=Autowire.BY_TYPE)&或者&@Configurable(autowire=Autowire.BY_NAME,这样就可以按类型或者按名字自动装配了。
Marks a class as being eligible for Spring-driven configuration.
Typically used with the AspectJ AnnotationBeanConfigurerAspect.
public @interface Value:用于注入SpEL表达式,可以放置在字段方法或参数上。
Annotation at the field or method/constructor parameter level that indicates a default value expression for the affected argument.
Typically used for expression-driven dependency injection. Also supported for dynamic resolution of handler method parameters, e.g. in Spring MVC.
A common use case is to assign default field values using "#{systemProperties.myProp}" style expressions.
Note that actual processing of the @Value annotation is performed by a BeanPostProcessor which in turn means that you cannot use @Value within BeanPostProcessor or BeanFactoryPostProcessor types. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).
public @interface Qualifier:指定限定描述符,对应于基于XML配置中的&qualifier&标签,@Qualifier限定描述符除了能根据名字进行注入,但能进行更细粒度的控制如何选择候选者@Qualifier(value = "限定标识符")&。
This annotation may be used on a field or parameter as a qualifier for candidate beans when autowiring. It may also be used to annotate other custom annotations that can then in turn be used as qualifiers.
public @interface Required 依赖检查;
Marks a method (typically a JavaBean setter method) as being 'required': that is, the setter method must be configured to be dependency-injected with a value.
Please do consult the javadoc for the RequiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).
2. 注解bean的定义AnnotatedBeanDefinition
public interface AnnotatedBeanDefinition extends BeanDefinition {
* Obtain the annotation metadata (as well as basic class metadata)
* for this bean definition's bean class.
* @return the annotation metadata object (never {@code null})
AnnotationMetadata getMetadata();
& &该接口继承了BeanDefinition,提供了一个getMetadata()方法来获取该bean definition的注解元数据。
其中,AnnotationMetadata定义了访问特定类的注解的抽象接口,它不需要加载该类即可访问。
public interface AnnotationMetadata extends ClassMetadata, AnnotatedTypeMetadata {
ClassMetadata定义了一个特定类的抽象元数据,不需要加载此类。主要方法如下:
String getClassName()返回该类的名称。boolean isInterface()返回该类是否是接口。boolean isAbstract()返回该类是否为抽象类。boolean isConcrete()返回该类是否为具体类。boolean isFinal()返回该类是否为final类boolean hasSuperClass()返回该类是否有父类
String getSuperClassName()返回父类的名称,没有的话返回null.
String[] getInterfaceNames()返回继承的接口数组,如果没有,返回空.
String[] getMemberClassNames()返回引用的类的名称。
AnnotatedTypeMetadata定义访问特定类型的注解,不需要加载类。主要方法有:
boolean isAnnotated(String annotationType)是否有匹配的注解类型
Map&String,Object& getAnnotationAttributes(String annotationType,boolean classValuesAsString)获取特定类型注解的属性
AnnotationMetadata的标准实现类StandardAnnotationMetadata,它使用标准的反射来获取制定类的内部注解信息。主要方法有:
getAllAnnotationAttributes(String annotationType)
getAnnotatedMethods(String annotationType)
hasMetaAnnotation(String annotationType)
isAnnotated(String annotationType)
hasAnnotatedMethods(String annotationType)
AnnotationMetadata还有一个子类:AnnotationMetadataReadingVisitor,它是字节码访问实现。
class ClassMetadataReadingVisitor extends ClassVisitor implements ClassMetadata {
让我们了解一下visitor模式:
The&&defines the Visitor as:&"Represent an operation to be performed on elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates."&&P&
The nature of the Visitor makes it an ideal pattern to plug into public APIs thus allowing its clients to perform operations on a class using a &visiting& class without having to modify the source.
uml 结构图如下:
&小结:vistor设置模式把状态抽象出来成为一个接口(访问者),不同的状态就作为状态的不同实现类(不同的访问者)。
&3.&注解bean的实现类
& & 3.1&AnnotatedGenericBeanDefinition
& & & & & 继承了GenericBeanDefinition,增加了对注解元素的支持,这种支持是通过AnnotationBeanDefinition暴露的的注解元素接口。
   &GenericBeanDefinition主要用来测试AnnotatedBeanDefinition上的操作的,例如:在spring的component扫描支持的实现中(默认实现类是ScannedGenericBeanDefinition,它同样实现了AnnotatedBeanDefinition接口)
& 3.2&ConfigurationClassBeanDefinition
& &&ConfigurationClassBeanDefinition是ConfigurationClassBeanDefinitionReader的内部类,ConfigurationClassBeanDefinitionReader读取一组完全填充了属性的配置实例,通过context内给定的BeanDefinitionRegistry进行注册bean definition。这个类在BeanDefinitionReader这层后就改造,但没有继承或者扩展配置类。
& &3.3&ScannedGenericBeanDefinition
&  基于asm的类解析器,是GenericBeanDefinition类的扩展,支持注解元数据,这种支持通过AnnotatedBeanDefinition接口实现。
4. 注解的解析与处理
4.1 @Autowired注解实现AutowiredAnnotationBeanPostProcessor
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
AutowiredAnnotationBeanPostProcessor 间接继承了BeanPostProcessor,它自动绑定注解的field,setter方法和任意的配置方法。当检测到5个java注解时这些成员被注入其中。spring默认的注解为@Autowired和@Value。另外:也支持JSR-330的@inject注解,作为@Autowired的替代方案。当制定bean 类的唯一构造方法带有required 注解参数,且required值设置为true时,表明当作为spring一个bean时,构造方法默认自动绑定。若多个构造方法带有non-required 注解参数,它们将作为自动绑定的候选项。带有大量依赖的构造方法可以通过spring容器中的匹配的bean来构造,如果没有候选者满足条件,则会使用默认的构造器。注解构造器不一定是public的。Field注入是在构造方法之后,配置方法之前,这种配置field不要求一定为public配置方法可以有任意的名称和不定的参数列表,这些参数则被自动注入到spring容器中的匹配的bean。bean的属性setter方法仅仅是通用的配置方法的一个特例而已。配置方法不要求方法一定为public注意:默认注册AutowiredAnnotationBeanPostProcessor的方式有&context:annotation-config& 和&context:component-scan& xml标签,如果你指定了一个自定义的AutowiredAnnotationBeanPostProcessor bean definition,移除或者关闭默认的注解配置。
其中,MergedBeanDefinitionPostProcessor的定义如下:
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor {
* Post-process the given merged bean definition for the specified bean.
* @param beanDefinition the merged bean definition for the bean
* @param beanType the actual type of the managed bean instance
* @param beanName the name of the bean
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class&?& beanType, String beanName);
BeanPostProcessor 是一个可以定制修改一个新的bean实例的工厂钩子,例如:检查marker接口或者使用代理包装他们。applicationContext可以在他们的bean容器中自动识别BeanPostProcessor bean,并将它们应用到接下来所创建的bean。一般的bean factory通过编程来注册Post-processor,并将它们应用到整个bean factory创建bean的过程中。通常意义上,post-processor 设置bean属性通过marker 接口或者类似于实现postProcessBeforeInitialization(java.lang.Object, java.lang.String);使用代理包装bean通常实现postProcessAfterInitialization(java.lang.Object, java.lang.String).
4.2 @configurable注解实现AnnotationBeanWiringInfoResolver&
设置&@Configurable&注解中的autowire属性就可以让Spring来自动装配了:&@Configurable(autowire=Autowire.BY_TYPE)&或者&@Configurable(autowire=Autowire.BY_NAME,这样就可以按类型或者按名字自动装配了。
& &&AnnotationBeanWiringInfoResolver 继承自BeanWiringInfoResolver,BeanWiringInfoResolver使用configurable注解来查找哪些类需要自动绑定。
public class AnnotationBeanWiringInfoResolver implements BeanWiringInfoResolver {
实现了BeanWiringInfoResolver的resolveWiringInfo方法
public BeanWiringInfo resolveWiringInfo(Object beanInstance) {
Assert.notNull(beanInstance, "Bean instance must not be null");
Configurable annotation = beanInstance.getClass().getAnnotation(Configurable.class);
return (annotation != null ? buildWiringInfo(beanInstance, annotation) : null);
* Build the BeanWiringInfo for the given Configurable annotation.
* @param beanInstance the bean instance
* @param annotation the Configurable annotation found on the bean class
* @return the resolved BeanWiringInfo
protected BeanWiringInfo buildWiringInfo(Object beanInstance, Configurable annotation) {
if (!Autowire.NO.equals(annotation.autowire())) {
return new BeanWiringInfo(annotation.autowire().value(), annotation.dependencyCheck());
if (!"".equals(annotation.value())) {
// explicitly specified bean name
return new BeanWiringInfo(annotation.value(), false);
// default bean name
return new BeanWiringInfo(getDefaultBeanName(beanInstance), true);
&4.3 @qualifier的注解实现类QualifierAnnotationAutowireCandidateResolver
public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwareAutowireCandidateResolver {
public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandidateResolver, BeanFactoryAware {
其中,AutowireCandidateResolver是一个策略接口,由它来决定特定的bean definition对特定的依赖是否可以作为一个自动绑定的候选项,它的主要方法有:
boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor)
Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor,String beanName)
Object getSuggestedValue(DependencyDescriptor descriptor)
&QualifierAnnotationAutowireCandidateResolver间接实现了AutowireCandidateResolver,对要自动绑定的field或者参数和bean definition根据@qualifier注解进行匹配。同时也支持通过@value注解来绑定表达式的值。
另外,还只是JSR-330的javax.inject.Qualifier注解。
4.4 @required注解实现类RequiredAnnotationBeanPostProcessor。
public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {
和AutowiredAnnotationBeanPostProcessor一样,间接继承自BeanPostProcessor,它增加了对javaBean属性配置的约束,java 5 注解可以检测bean的required属性,spring默认是@Required注解。
注意:默认注册AutowiredAnnotationBeanPostProcessor的方式有&context:annotation-config& 和&context:component-scan& xml标签,如果你指定了一个自定义的
默认注册AutowiredAnnotationBeanPostProcessor的方式有&context:annotation-config& 和&context:component-scan& xml标签,如果你指定了一个自定义的AutowiredAnnotationBeanPostProcessor bean definition,移除或者关闭默认的注解配置。其余和AutowiredAnnotationBeanPostProcessor类似,不一一赘述了。
4.5 初始化和销毁方法的注解实现类InitDestroyAnnotationBeanPostProcessor
public class InitDestroyAnnotationBeanPostProcessor
implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {
InitDestroyAnnotationBeanPostProcessor间接继承了BeanPostProcess,实现了通过注解来初始化和销毁方法,是spring的InitializingBean和DisposableBean回调接口的注解实现。
它通过"initAnnotationType"和"destroyAnnotationType"属性来检查指定的注解类型,任何自定义的注解都可以使用。
初始化和销毁注解可以用在任意可见的方法:public,package-protected,protected,private等。尽管可以对多个方法进行注解,但我们推荐只在一个初始化和销毁方法上各自进行注解。
&Spring3的基于注解实现Bean依赖注入支持如下三种注解:Spring自带依赖注入注解: Spring自带的一套依赖注入注解;JSR-250注解:Java平台的公共注解,是Java EE 5规范之一,在JDK6中默认包含这些注解,从Spring2.5开始支持。JSR-330注解:Java 依赖注入标准,Java EE 6规范之一,可能在加入到未来JDK版本,从Spring3开始支持;
其中,Spring自带依赖注入注解1 @Required:依赖检查;2 @Autowired:自动装配2&自动装配,用于替代基于XML配置的自动装配基于@Autowired的自动装配,默认是根据类型注入,可以用于构造器、字段、方法注入3 @Value:注入SpEL表达式用于注入SpEL表达式,可以放置在字段方法或参数上@Value(value = "SpEL表达式") &@Value(value = "#{message}") &4 @Qualifier:限定描述符,用于细粒度选择候选者@Qualifier限定描述符除了能根据名字进行注入,但能进行更细粒度的控制如何选择候选者@Qualifier(value = "限定标识符")&JSR-250注解1 @Resource:自动装配,默认根据类型装配,如果指定name属性将根据名字装配,可以使用如下方式来指定@Resource(name = "标识符") &字段或setter方法&
2 @PostConstruct和PreDestroy:通过注解指定初始化和销毁方法定义
JSR-330注解1 @Inject:等价于默认的@Autowired,只是没有required属性2 @Named:指定Bean名字,对应于Spring自带@Qualifier中的缺省的根据Bean名字注入情况3 @Qualifier:只对应于Spring自带@Qualifier中的扩展@Qualifier限定描述符注解,即只能扩展使用,没有value属性
参考文献:
1. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/annotation/
2. http://blog.csdn.net/wangshfa/article/details/9712379
阅读(...) 评论()下次自动登录
现在的位置:
& 综合 & 正文
Spring常用注解,自动扫描装配Bean
1 引入context命名空间(在Spring的配置文件中),配置文件如下:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
打开配置 &context:component-scan base-package="包名(扫描本包及子包)"/&
spring 会自动扫描cn.pic包下面有注解的类,完成Bean的装配。
version="1.0" encoding="UTF-8"
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-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd"
base-package="cn.pic"
2 在classPath中加入注解用的jar包
lib\j2ee\common-annotations.jar
Spring 的context:component-scan扫描支持扫描jar包的方法:
eclipse自带的jar打包,默认打包的时候有个选项&Add directory entries&没有勾选,只要勾选了,就可以了.
-----------常用注解--------
--定义Bean的注解
@Controller
@Controller("Bean的名称")
定义控制层Bean,如Action
@Service("Bean的名称")
定义业务层Bean
@Repository
@Repository("Bean的名称")
定义DAO层Bean
@Component
定义Bean, 不好归类时使用.
--自动装配Bean (选用一种注解就可以)
@Autowired
(Srping提供的)
默认按类型匹配,自动装配(Srping提供的),可以写在成员属性上,或写在setter方法上
@Autowired(required=true)
一定要找到匹配的Bean,否则抛异常。 默认值就是true
@Autowired
@Qualifier("bean的名字")
按名称装配Bean,与@Autowired组合使用,解决按类型匹配找到多个Bean问题。
JSR-250提供的
默认按名称装配,当找不到名称匹配的bean再按类型装配.
可以写在成员属性上,或写在setter方法上
可以通过@Resource(name="beanName") 指定被注入的bean的名称, 要是未指定name属性, 默认使用成员属性的变量名,一般不用写name属性.
@Resource(name="beanName")指定了name属性,按名称注入但没找到bean, 就不会再按类型装配了.
是JSR-330提供的
按类型装配,功能比@Autowired少,没有使用的必要。
--定义Bean的作用域和生命过程
@Scope("prototype")
值有:singleton,prototype,session,request,session,globalSession
@PostConstruct
相当于init-method,使用在方法上,当Bean初始化时执行。
@PreDestroy
相当于destory-method,使用在方法上,当Bean销毁时执行。
--声明式事务
@Transactional
&&&&推荐文章:
【上篇】【下篇】J2EE &&&&最新内容
J2EE &&&&随机内容Spring bean init-method方法中不能有查询数据库的操作吗?
[问题点数:100分,结帖人sunshine_love]
Spring bean init-method方法中不能有查询数据库的操作吗?
[问题点数:100分,结帖人sunshine_love]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2013年10月 总版技术专家分月排行榜第三
2014年3月 Java大版内专家分月排行榜第一2014年1月 Java大版内专家分月排行榜第一2013年12月 Java大版内专家分月排行榜第一2013年11月 Java大版内专家分月排行榜第一2013年10月 Java大版内专家分月排行榜第一
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。spring注解bean加载顺序问题(一)
最近在项目中遇到了一个问题:关于bean的加载顺序问题,在这里简单讲解一下.
背景:项目框架组成:wicket+jdbc+spring,并且spring用的是注解方式,注解配置如下:
& & &&context:component-scan base-package=&com.kb.core&&&/context:component-scan&
& & &&context:component-scan base-package=&com.kb.service&&&/context:component-scan&
& & &&context:component-scan base-package=&com.kb.dao&&&/context:component-scan&
& & &&context:component-scan base-package=&com.kb.web&&&/context:component-scan&
需求:在系统启动的时候需要初始化数据库,此工具类DbUtil存在core包下,并且由 @Component注解,即把普通类实例化到spring容器中.
& & &因为DbUtil作用是初始化数据库,所以需要在此类中获取service bean以存入数据到数据库,但初始化此工具类的时候所有的
& & &service bean和dao bean还未实例化到spring容器中(原因是扫描包的顺序是core-service-dao-web),所以会报异常,怎么解决呢?
方法:可以通过获取SpringApplicationContextFactory获取service bean,然后存入数据库,代码如下.& &&&span style=&;&& @Component
public class SpringApplicationContextFactory implements ApplicationContextAware {
private static ApplicationContext applicationC
public void setApplicationContext(ApplicationContext ac) throws BeansException {
applicationContext =
public static ApplicationContext getApplicationContext(){
return applicationC
}&/span&问题:按照如上解决方法,仍然会在DbUtil类中报空指针异常,并且空指针指向SpringApplicationContextFactory?
分析:问题很简单:就是spring容器在实例化DbUtil的时候SpringApplicationContextFactory还未被实例化,即涉及到一个bean的实例化顺序问题.
& & &但是无论是DbUtil还是SpringApplicationContextFactory都是由 @Component注解,怎么解决呢?
方法:解决方法很简单,spring扫描机制是按照配置扫描包,并且每个包下的bean也是由上向下进行扫描.
& & &所以只需要将SpringApplicationContextFactory类放在DbUtil类前面即可.如将SpringApplicationContextFactory改名为ASpringApplicationContextFactory就OK了.
更多相关文章
问题来源: 有一个bean为A,一个bean为B.想要A在容器实例化的时候的一个属性name赋值为B的一个方法funB的返回值. 如果只是在A里单纯的写着: private B private String name = b.funb(); 会报错说nullpointException,因为这 ...
/blog/1273031 问题来源: 有一个bean为A,一个bean为B.想要A在容器实例化的时候的一个属性name赋值为B的一个方法funB的返回值. 如果只是在A里单纯的写着: private B private String name
首先给大家看一个范例java代理的范例: public class MyInvocationHandler implements InvocationHandler { // 目标对象,也就是我们主要的业务,主要目的要做什么事 private O / * 和你额外需要做 ...
/ * 系统配置 */ package mon. import java.util.M import javax.annotation.PostC import org.springframework.beans.factory.anno ...
web.xml 文件中一般包括 servlet, spring, filter, listenr的配置.那么他们是按照一个什么顺序加载呢? 加载顺序会影响对spring bean 的调用.
比如filter 需要用到 bean ,但是加载顺序是 先加载filter 后加载spring,则fi ...
web.xml 文件中一般包括 servlet, spring, filter, listenr的配置.那么他们是按照一个什么顺序加载呢? 加载顺序会影响对spring bean 的调用.
比如filter 需要用到 bean ,但是加载顺序是 先加载filter 后加载spring,则fi ...
类A托管给spring,类A里有一属性B,且有B的Set方法,且类A实现了InitializingBean,及init()方法,则类A的初始化顺序为: 先A的构造函数-----&B的set方法------&afterPropertiesSet方法里执行的内容------&init( ...
Spring中的配置文件,一般情况下命名为applicationContext.xml,myeclipse会自动用spring编辑器进行编辑.加载顺序:1.首先读取配置配置文件,扫描所有的配置的bean对象,将其实例化.(因为懒加载的原因,某些情况下如果客户端没有getbean的话不会为该bean实 ...
1.为什么会出现系统调用被中断的情况? 进程在执行一个低速系统调用而阻塞期间捕捉到一个信号时,该系统调用就被中断不再继续执行.该系统调用返回出错,其errno被设置为EINTR.这样处理的理由是:因为一个信号发生了, ...
运维过程中,有时需要快速查找HBA卡的WWN号,现把几种常见的系统下查找WWN号的方法总结一下. AIX: 1,获得AIX主机连接的光纤设备: # lsdev -Cc adapter -S a | grep fcs
scan windows:创建扫描任务的时候,指定扫描时间范围的一个参数.对于常规的设置, ...
2.5 数据类型的转换 Java中变量的数据类型在变量定义时就已被确定,因此不能随意地转换 ...
AN2820 Driving bipolar stepper motors using a ...
// 用单例模式实现自定义颜色类 public class MyColor { private static MyColor _redColor = public static MyColor GetRe ...
[功能描述]系统数据库备份还原.[操作说明]后台登陆-系统-数据库备份/还原.[应用实例] ...
近日,Windows 10 Build 10036界面截图在网络上泄漏,相比较此前官方发布 ...
原文出处:11-running_the_test_suite.md 原文作者:FriendsOfSymfony 授权许可:创作共用协议 翻译人员:FireHare 校对人员: 适用版本:FOSCommentBundl ...
易网邮箱和GMAIL都是使用人数很多的邮件,易网邮箱的客户主要集中在国内,据说邮箱国内邮箱市场占有率占了60%,这是一个非常大的数字,那说明易网邮箱确实做得不错,我个人也比较喜欢他的风格和操作方式,速度上也是 ...

我要回帖

更多关于 factory method 注解 的文章

 

随机推荐