Spring解惑Ⅰ

Spring解惑Ⅰ
     相信用过spring的人肯定写过这样一段代码:
    
1 Resource 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:
 1 package  com.spring.entrance;
 2
 3 public   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;

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

10 public   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 的源码:
    
1 public 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

    明天周一了,继续工作。加油!

你可能感兴趣的:(Spring解惑Ⅰ)