I want to fly higher
programming Explorer
posts - 114,comments - 263,trackbacks - 0
    相信用过spring的人肯定写过这样一段代码:
    
1Resource resource = new FileSystemResource("res/springconf.xml");
2     BeanFactory factory = new XmlBeanFactory(resource);
3
4     HelloBean helloBean = (HelloBean)factory.getBean("helloBean");
5  
6     System.out.println(helloBean.getSpringInfo());
7
     
     当然Bean和XML有可能不同,下面贴出我写的一个简单的HelloBean和一个简单的spring配置文件springconf.xml:
HelloBean.java:
 1package com.spring.entrance;
 2
 3public class HelloBean
 4{
 5 private String springInfo;
 6 
 7 /**
 8  * 显示的public构造函数
 9  */

10 public HelloBean()
11 {
12  System.out.println("构造函数初始化");
13 }

14 
15 /**
16  * 
17  * setter
18  * 
19  * @param info
20  */

21 public void setSpringInfo(String info)
22 {
23  this.springInfo = info;
24 }

25 
26 /**
27  * 
28  * getter
29  * 
30  * @return
31  */

32 public String getSpringInfo()
33 {
34  return springInfo;
35 }

36}

37
38

springconf.xml:

<?xml version="1.0" encoding="UTF-8"?>   
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
  
<beans>   
 
<bean name="helloBean" class="com.spring.entrance.HelloBean">
  
<property name="springInfo" value="hello,spring" />
 
</bean>
</beans>

 


    大家仔细看一下,我特意在构造函数这里添加了一句打印信息,因为我想看看spring容器是如何初始化对象的。输出结果显而易见,首先执行执行了构造函数的打印语句,然后打印出了配置文件注入的属性值。不过马上我要和大家讨论的是,如果我将HelloBean的构造函数改成私有的构造函数结果会怎么样呢?
    于是我将HelloBean的构造函数的修饰符public改成了private,然后运行,看结果,令我很诧异,构造函数中的打印语句仍然执行。让我诧异的原因是spring容器竟然可以调用我的私有构造函数。起初,我想到这个问题是因为在做项目的时候,我想做一个单例的管理器,即构造函数私有,然后利用懒汉式或者饿汉式的方式来创建单例对象。不过因为项目的原因,一些类的实例化工作是利用spring做的,即你只需要在xml中配置一个bean即可。
    这让我对spring容器有了莫大的兴趣,发现之前对spring的理解有许多的不足,下面我就解惑spring到底是如何创建对象的:
    首先可以肯定的是,spring是利用反射机制来创建对象的,可到底是怎么样利用反射创建的?下面我再写一个demo:

package com.spring.entrance;

 1import java.lang.reflect.Constructor;
 2
 3/**
 4 * 
 5 * 利用反射构造私有类对象
 6 * 
 7 * @author landon
 8 *
 9 */

10public class ReflectConstructDemo 
11{
12 public static void main(Stringargs)
13 {
14  try
15  {
16   Constructor [] constructors = Class.forName("com.spring.entrance.HelloBean").getDeclaredConstructors();
17   
18   for(int i = 0;i < constructors.length;i++)
19   {
20    constructors[i].newInstance();
21   }

22  }

23  catch(SecurityException e)
24  {
25   System.out.println(e.getMessage());
26  }

27  catch(ClassNotFoundException e)
28  {
29   System.out.println(e.getMessage());
30  }

31  catch(Exception e)
32  {
33   e.printStackTrace();
34  }

35 }

36}

37
38

 

    注意这里,HelloBean的构造函数依然是私有的。然后我们看运行结果:

java.lang.IllegalAccessException: Class com.spring.entrance.ReflectConstructDemo can not access a member of class com.spring.entrance.HelloBean with modifiers "private"
 at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
 at java.lang.reflect.Constructor.newInstance(Unknown Source)
 at com.spring.entrance.ReflectConstructDemo.main(ReflectConstructDemo.java:22)

    运行结果出现异常,提示是不能访问私有的构造函数,那下面该怎么办呢?我在newInstance之前加上一句代码:constructors[i].setAccessible(true);然后运行程序,我们发现顺利的打印出了私有构造函数的语句
    看来确实可以利用反射机制来运行时构造一个类,而不管其是private有的还是public的。如果大家有兴趣的话,还可以反编译一下Constructor的源码:
    
1public transient Object newInstance(Object aobj[])
2 throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
3 {
4 if(!override && !Reflection.quickCheckMemberAccess(clazz, modifiers))
5 {
6 Class class1 = Reflection.getCallerClass(2);
7 if(securityCheckCache != class1)
8 {
9 Reflection.ensureMemberAccess(class1, clazz, null, modifiers);
10 securityCheckCache = class1;
11 }

12 }

13 if((clazz.getModifiers() & 16384) != 0)
14 throw new IllegalArgumentException("Cannot reflectively create enum objects");
15 if(constructorAccessor == null)
16 acquireConstructorAccessor();
17 return constructorAccessor.newInstance(aobj);
18 }

19

    我们可以看到第一次没有加上constructors[i].setAccessible(true)这句代码之前的运行结果抛出的异常就是由ensureMemberAccess这个方法调用所抛出来的IllegalAccessException。
    哈哈,问题终于搞懂了。看来反射机制确实很nb,spring的东西也确实不错,以后继续学习。之前我写过一篇反射机制和Annotation的blog,大家可以参考-http://www.blogjava.net/landon/archive/2010/07/14/326071.html

    明天周一了,继续工作。加油!
posted on 2010-12-12 16:45 landon 阅读(1758) 评论(4)  编辑  收藏 所属分类: Program

FeedBack:
# re: Spring解惑1
2010-12-12 18:48 | **
只是解你自己的惑!别把标题写那么大。  回复  更多评论
  
# re: Spring解惑1
2010-12-12 19:18 | landonlv
我是解自己的惑啊。也许你是行家,觉得这东西无所谓。我只是分享出来罢了。欢迎评论@**
  回复  更多评论
  
# re: Spring解惑1[未登录]
2010-12-13 14:05 | abc
写的不错。感谢分享!  回复  更多评论
  
# re: Spring解惑1
2010-12-13 22:29 | landonlv
嗯,大家互相学习@abc
  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: