Spring BeanFactory getBean 源码剖析
2015-09-03 19:28
465 查看
首先看一张时序图
最开始,一切都来自这里:
如果我们是通过BeanFactory来构造IoC容器的话,那就是直接从上面的时序图的第五步开始
[java] view
plaincopy
public static void main(String[] args){
Resource resource=new ClassPathResource("applicationContext2.xml");
BeanFactory factory=new DefaultListableBeanFactory();
BeanDefinitionReader bdr=new XmlBeanDefinitionReader((BeanDefinitionRegistry) factory);
bdr.loadBeanDefinitions(resource);
String url=((FXNewsBean) factory.getBean("newsBean2")).getUrl();
System.out.println(url);
}
当然,ApplicatonContext有缓存机制,在容器启动的时候,就加载了所有的bean,并缓存之,如果有了显式或隐式的调用,直接从缓存里拿就是了
********************
我们从上面的代码很容易追踪到AbstractBeanFactory的doGetBean方法
[java] view
plaincopy
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//*************************1
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//*************************2
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//判断要获得的bean是否实现了FactoryBean,是获得工厂本身还是获得工厂生产的产品
//如果要获得工厂本身 beanName就要以&开头
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
//下面这个是关于循环依赖的处理
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
//如果存在父容器,且当前容器中不存在要获取的对象 那就去父容器去找
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//typeCheckOnly参数 调用是就是false
//标明这个beanname已经被创建了
//后面会用到
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
//*************************3
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
//*************************4
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
}
// Create bean instance.
//*************************5
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type [" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
代码1处,转化有两个步骤,首先处理beanName为&XXX的格式,这里表示要取指定name的factoryBean。在这里先把&符号取消,先获取bean再处理。然后,针对bean的alias机制,这里传入的参数可能是一个bean别名,那么我们先获取这个bean的主要id,只需要根据id值取bean就可以了。
代码2处,就是依次检查缓存。如果缓存里有,就直接拿出来。
spring的缓存有3种
之前已经获取过的bean
手动注入的bean
手动注入的ObjectFactory
第一种缓存好理解,看一下下面的代码,大家就知道手动注入bean与ObjectFctory是怎么回事了。
[java] view
plaincopy
public static void main(String[] args){
Resource resource=new ClassPathResource("applicationContext2.xml");
BeanFactory factory=new DefaultListableBeanFactory();
BeanDefinitionReader bdr=new XmlBeanDefinitionReader((BeanDefinitionRegistry) factory);
bdr.loadBeanDefinitions(resource);
FXNewsBean fx=new FXNewsBean();
fx.setUrl("Thank glt");
//同时还有一个方法叫addSingletonFactory
((DefaultSingletonBeanRegistry) factory).registerSingleton("newsBean2",fx);
FXNewsBean news=(FXNewsBean) factory.getBean("newsBean2");
System.out.println(news.getUrl()); //打印出Thank glt
}
[java] view
plaincopy
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
代码3处,麻烦的是是getMergedLocalBeanDefinition(beanName)。这个处理的主要是bean的present信息与scope信息。
说实话,这部分我没有看。
下面就是检查bean了。
首先,这个bean不能是abstract的。其次,如果getBean时还传递了要获取bean的参数(这里指构造方法的参)并且这个bean是singleton,那就得报错。
为什么?你想呀
factory.getBean("myBean","aaaa");
factory.getBean("myBean","bbbb");
如果myBean这个对象是singleton,上面的两行代码获得的对象能相等吗?
所以只能报错了。
[java] view
plaincopy
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
}
代码4处,如果BeanA中引用了BeanB,那么再getBean("BeanA")时就会先getBean("BeanB");
之后,注册依赖关系。
这个依赖关系有什么用呢?
似乎是在销毁类时用的,我不是很清楚。
代码5
如果要获取的bean是单例的
[java] view
plaincopy
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
}
注意上面的代码其实只有一行。
即调用getSingleton方法。
只不过getSingleton的第二个参数是一个匿名内部类。
这个内部类有一个getObject方法。,里面调用的是外部类的方法createBean。(外部类是谁?是AbstractBeanFactory)
我们先看getSingleton
[java] view
plaincopy
public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
singletonObject = singletonFactory.getObject();
addSingleton(beanName, singletonObject);//添加到已成功创建列表中 这是缓存
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
getSingleton省略了一些代码,主要是验证
getSingleton里面调用getObject就跑到了匿名类里面,最后的是AbstractBeanFactory的createBean方法。
不过AbstractBeanFactory中creatBean是abstract的。
实现在它的子类----AbstractAutowireCapableBeanFactory
[java] view
plaincopy
@Override
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
// Make sure bean class is actually resolved at this point.
//*************************5.1 保证RootBeanDefinition里面有beanclass
resolveBeanClass(mbd, beanName);
// Prepare method overrides.
try {
//*************************5.2 方法注入
mbd.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
//*************************5.3
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
//*************************5.4
Object beanInstance = doCreateBean(beanName, mbd, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
关于5.2处的代码,它处理的类似这样的bean。 更多信息可查看 http://blog.csdn.net/dlf123321/article/details/47862175
[java] view
plaincopy
<bean id="mockPersister" class="..impl.MockNewsPersister">
<lookup-method name="getNewsBean" bean="newsBean"/>
</bean>
关于5.3处的代码,得提到一个接口InstantiationAwareBeanPostProcessor,它本身也继承了BeanPostProcessor接口。
我们看到了在5.3代码的下面一旦resolveBeforeInstantiation的返回值不是null,那么直接就return。
resolveBeforeInstantiation类似于一个"短路器",执行了resolveBeforeInstantiation后(我是指getBean的对象实现了InstantiationAwareBeanPostProcessor接口,并且postProcessBeforeInstantiation方法的返回值不为null)下面的流程就不走了,直接返回bean。
这个方法一般情况下返回的都是null,通常情况下都是Spring容器内部使用这种特殊类型的BeanPostProcessor做一些动态对象代理等工作,我们使用普通的BeanPostProcessor实现就可以。这里简单提及一下,目的是让大家有所了解。
历尽千辛万苦,我们终于到了5.4了
让我歇会,下一节我们聊doCreatBean。
参考资料
http://michael-softtech.iteye.com/blog/816469 spring源码分析之——spring bean的获取
http://www.iflym.com/index.php/code/201208290001.html Spring中获取一个bean的流程-1
<<spring揭秘>> 第四章 79页
版权声明:本文为博主原创文章,未经博主允许不得转载。
最开始,一切都来自这里:
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext3.xml"); context.getBean("newsBean"); }
如果我们是通过BeanFactory来构造IoC容器的话,那就是直接从上面的时序图的第五步开始
[java] view
plaincopy
public static void main(String[] args){
Resource resource=new ClassPathResource("applicationContext2.xml");
BeanFactory factory=new DefaultListableBeanFactory();
BeanDefinitionReader bdr=new XmlBeanDefinitionReader((BeanDefinitionRegistry) factory);
bdr.loadBeanDefinitions(resource);
String url=((FXNewsBean) factory.getBean("newsBean2")).getUrl();
System.out.println(url);
}
当然,ApplicatonContext有缓存机制,在容器启动的时候,就加载了所有的bean,并缓存之,如果有了显式或隐式的调用,直接从缓存里拿就是了
********************
我们从上面的代码很容易追踪到AbstractBeanFactory的doGetBean方法
[java] view
plaincopy
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//*************************1
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
//*************************2
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//判断要获得的bean是否实现了FactoryBean,是获得工厂本身还是获得工厂生产的产品
//如果要获得工厂本身 beanName就要以&开头
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
//下面这个是关于循环依赖的处理
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
//如果存在父容器,且当前容器中不存在要获取的对象 那就去父容器去找
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//typeCheckOnly参数 调用是就是false
//标明这个beanname已经被创建了
//后面会用到
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
//*************************3
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
//*************************4
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
}
// Create bean instance.
//*************************5
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; " +
"consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type [" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
代码1处,转化有两个步骤,首先处理beanName为&XXX的格式,这里表示要取指定name的factoryBean。在这里先把&符号取消,先获取bean再处理。然后,针对bean的alias机制,这里传入的参数可能是一个bean别名,那么我们先获取这个bean的主要id,只需要根据id值取bean就可以了。
代码2处,就是依次检查缓存。如果缓存里有,就直接拿出来。
spring的缓存有3种
之前已经获取过的bean
手动注入的bean
手动注入的ObjectFactory
第一种缓存好理解,看一下下面的代码,大家就知道手动注入bean与ObjectFctory是怎么回事了。
[java] view
plaincopy
public static void main(String[] args){
Resource resource=new ClassPathResource("applicationContext2.xml");
BeanFactory factory=new DefaultListableBeanFactory();
BeanDefinitionReader bdr=new XmlBeanDefinitionReader((BeanDefinitionRegistry) factory);
bdr.loadBeanDefinitions(resource);
FXNewsBean fx=new FXNewsBean();
fx.setUrl("Thank glt");
//同时还有一个方法叫addSingletonFactory
((DefaultSingletonBeanRegistry) factory).registerSingleton("newsBean2",fx);
FXNewsBean news=(FXNewsBean) factory.getBean("newsBean2");
System.out.println(news.getUrl()); //打印出Thank glt
}
[java] view
plaincopy
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
代码3处,麻烦的是是getMergedLocalBeanDefinition(beanName)。这个处理的主要是bean的present信息与scope信息。
说实话,这部分我没有看。
下面就是检查bean了。
首先,这个bean不能是abstract的。其次,如果getBean时还传递了要获取bean的参数(这里指构造方法的参)并且这个bean是singleton,那就得报错。
为什么?你想呀
factory.getBean("myBean","aaaa");
factory.getBean("myBean","bbbb");
如果myBean这个对象是singleton,上面的两行代码获得的对象能相等吗?
所以只能报错了。
[java] view
plaincopy
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
getBean(dependsOnBean);
registerDependentBean(dependsOnBean, beanName);
}
}
代码4处,如果BeanA中引用了BeanB,那么再getBean("BeanA")时就会先getBean("BeanB");
之后,注册依赖关系。
这个依赖关系有什么用呢?
似乎是在销毁类时用的,我不是很清楚。
代码5
如果要获取的bean是单例的
[java] view
plaincopy
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
}
注意上面的代码其实只有一行。
即调用getSingleton方法。
只不过getSingleton的第二个参数是一个匿名内部类。
这个内部类有一个getObject方法。,里面调用的是外部类的方法createBean。(外部类是谁?是AbstractBeanFactory)
我们先看getSingleton
[java] view
plaincopy
public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
singletonObject = singletonFactory.getObject();
addSingleton(beanName, singletonObject);//添加到已成功创建列表中 这是缓存
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
getSingleton省略了一些代码,主要是验证
getSingleton里面调用getObject就跑到了匿名类里面,最后的是AbstractBeanFactory的createBean方法。
不过AbstractBeanFactory中creatBean是abstract的。
实现在它的子类----AbstractAutowireCapableBeanFactory
[java] view
plaincopy
@Override
protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
// Make sure bean class is actually resolved at this point.
//*************************5.1 保证RootBeanDefinition里面有beanclass
resolveBeanClass(mbd, beanName);
// Prepare method overrides.
try {
//*************************5.2 方法注入
mbd.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
//*************************5.3
Object bean = resolveBeforeInstantiation(beanName, mbd);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
//*************************5.4
Object beanInstance = doCreateBean(beanName, mbd, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
关于5.2处的代码,它处理的类似这样的bean。 更多信息可查看 http://blog.csdn.net/dlf123321/article/details/47862175
[java] view
plaincopy
<bean id="mockPersister" class="..impl.MockNewsPersister">
<lookup-method name="getNewsBean" bean="newsBean"/>
</bean>
关于5.3处的代码,得提到一个接口InstantiationAwareBeanPostProcessor,它本身也继承了BeanPostProcessor接口。
我们看到了在5.3代码的下面一旦resolveBeforeInstantiation的返回值不是null,那么直接就return。
resolveBeforeInstantiation类似于一个"短路器",执行了resolveBeforeInstantiation后(我是指getBean的对象实现了InstantiationAwareBeanPostProcessor接口,并且postProcessBeforeInstantiation方法的返回值不为null)下面的流程就不走了,直接返回bean。
这个方法一般情况下返回的都是null,通常情况下都是Spring容器内部使用这种特殊类型的BeanPostProcessor做一些动态对象代理等工作,我们使用普通的BeanPostProcessor实现就可以。这里简单提及一下,目的是让大家有所了解。
历尽千辛万苦,我们终于到了5.4了
让我歇会,下一节我们聊doCreatBean。
参考资料
http://michael-softtech.iteye.com/blog/816469 spring源码分析之——spring bean的获取
http://www.iflym.com/index.php/code/201208290001.html Spring中获取一个bean的流程-1
<<spring揭秘>> 第四章 79页
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关文章推荐
- Spring Mail
- Java基础针对自己薄弱环节总结07(递归、IO流)
- Java创建线程的两种方法
- java FutureTask的简单用法示例
- java简单的字符串大小比较——compareTo()方法
- 细说Java多线程之内存可见性
- java中连接数据库操作的语句,获得执行sql语句对数据库进行操作
- java_继承、super、重写、instanceof
- class org.springframework.scheduling.quartz.CronTriggerBean has interface org.quartz.CronTrigger as
- Java基础-内部类及其应用
- myeclipse2014配置spring
- Java记录 -21- 访问控制符
- 在Struts2中jsp前台传值到action后台的方法
- Java进程优雅关闭
- Java记录 -20- 包与导入语句
- java 中的Exception RuntimeException 区别
- java_单例设计模式
- spring ioc原理分析
- java线程同步实例
- 2015年秋季阿里巴巴在线笔试——Java研发师——部分试题分析