`
wzf7065
  • 浏览: 240009 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

Spring的xml配置bean文件原理-[Java反射机制]

 
阅读更多

原文来源:http://blog.csdn.net/zhang6622056/article/details/7659489

 

[javascript] view plaincopy
 
  1. 知道Spring在xml文件里面配置bean的方式,但是它是如何将对象赋值过去的呢?就是通过xml解析+Java反射。Xml解析可用jdom或者dom4j。网络上一找一大堆。下面我们就来说说Java的反射和内省:  
  2.   
  3. 反射:Java Reflection  
  4. Java反射机制具有的功能:  
  5. 1、  在运行时判断任意一个对象所属的类  
  6. 2、  在运行时构造任意一个类的对象  
  7. 3、  在运行时判断任意一个类具有的成员标量和方法  
  8. 4、  在运行时调用任意一个对象的方法  
  9. 生成动态代理  
  10. 通俗的说:  
  11.   反射就是让你可以通过名称来得到对象 ( 类,属性,方法 ) 的技术。  
  12.   例如我们可以通过类名来生成一个类的实例;  
  13.   知道了方法名,就可以调用这个方法;  
  14.   知道了属性名就可以访问这个属性的值。   
  15. 简单的反射案例:Class对象可以做很多操作。  
  16.     Class stu = Class.forName("cn.zhang.model.Student");  
  17.     Constructor[] stus = stu.getDeclaredConstructors();  
  18.     for(int i=0;i<stus.length;i++){  
  19.             System.out.println(stus[i].toString());  
  20.     }  
  21.     //得到实例  
  22.     Student s = (Student) stu.newInstance();  
  23. 1..加载类有三种方法   
  24. 加载类的3种方法  
  25.     第一种:  
  26.         Class cls1 = Class.forName("cn.csdn.reflect.Student");  
  27.     第二种:  
  28.         Student stu = new Student();  
  29.         Class cls2 = stu.getClass();  
  30.     第三种:  
  31.         Class cls3 = Student.class;  
  32.   
  33. 2.  要解析下面这个类的构造方法  
  34.     public class Student {  
  35.     private String name;  
  36.     private String sex;  
  37.     private int age;  
  38.     //无参构造  
  39.     public Student(){  
  40.     }  
  41.     //带两个参数的构造  
  42.     public Student(String name,int age){  
  43.         this.name=name;  
  44.         this.age=age;  
  45.     }  
  46.     //带一个数组参数的构造  
  47.     public Student(String strs[]){  
  48.         System.out.println(strs.length);  
  49.     }  
  50.       
  51.     //带一个集合类型参数的构造  
  52.     private Student(List list){  
  53.         System.out.println(list.size());  
  54.     }  
  55.     //一个普通的方法  
  56.     public void study(){  
  57.         System.out.println("good good study day day up");  
  58.     }  
  59.     public String getName(){  
  60.         return name;  
  61.     }  
  62.   
  63. }  
  64. 通过 Constructor csr[] = cls.getConstructors();我们可以得到Student 类中所有的构造方法的参数型  
  65.         然后我们遍历这个方法输出构造器参数的类型名称  
  66.         for(Constructor c:csr){  
  67. //for循环新特性参数解析:(集合里面存放的个体类型 集合的单个对象(自己起名):被遍历的对象集合)  
  68.             //打印出构造器参数的类型及构造器名称  
  69.              System.out.println(c.toGenericString());  
  70.         }     
  71.         运行的结果如下:  
  72.         public cn.csdn.reflect.Student() // 无参构造   
  73. public cn.csdn.reflect.Student(java.lang.String,int//带有两个参数的构造  
  74. public cn.csdn.reflect.Student(java.lang.String[])  //带有数组参数的构造   
  75.   
  76. 当我们得到所有造器参数的类型及构造器名称我们可以通过以下的方法来解析  
  77.   
  78.         // 解析无参构造:public Student()  
  79. public void test1() throws ClassNotFoundException, SecurityException,  
  80.             NoSuchMethodException, IllegalArgumentException,  
  81.             InstantiationException, IllegalAccessException,  
  82.             InvocationTargetException {  
  83.             // 1、加载类  
  84.             Class cls = Class.forName("cn.csdn.reflect.Student");  
  85.             // 2、通过无参数的构造器解析  
  86. // getConstructor() 方法返回一个 Constructor 对象,它反映此 Class //对象所表示的类的指定公共构造方法。  
  87. // parameterTypes 参数是 Class 对象的一个数组,这些 Class 对象按声//明顺序标识构造方法的形参类型。  
  88.             Constructor constructor = cls.getConstructor(null);    
  89. // 3、创建类的实例 , 通过newInstance() 方法可以创建一个实例 , 这就相当  
  90. //于 Student entity = new Student();  
  91.             Student entity = (Student) constructor.newInstance(null);  
  92.             //4、调用对象的方法  
  93.             entity.study();  
  94.         }  
  95.       
  96.   
  97.         //解析带有两个参数的构造:public Student(String name,int age);  
  98.         public void test2()throws Exception{  
  99.             //1、加载类  
  100.             Class cls = Class.forName("cn.csdn.reflect.Student");  
  101.             //2、通过带有参数的构造器解析  
  102. Constructor constructor = cls.getConstructor(String.class,int.class);  
  103.             //3、创建类实例  
  104. Student entity = (Student)constructor.newInstance("redarmy",90);  
  105.             //4、调用方法  
  106.             entity.study();  
  107.             System.out.println(entity.getName());  
  108.         }  
  109.       
  110.   
  111.          //解析数组参数的构造正确的写法:public Student(String strs[])  
  112.             public void test4()throws Exception{  
  113.             //1、加载类  
  114.             Class cls = Class.forName("cn.csdn.reflect.Student");  
  115.   
  116.             //2、根据构造器参数类型获取相应的构造器对象     
  117.             Constructor csr = cls.getConstructor(String[].class);  
  118.             String str[]={"111","123"};  
  119.             //3、创建实体对象  
  120.             Student entity = (Student)csr.newInstance((Object)str);  
  121.             //4、调用方法  
  122.             entity.study();  
  123.         }  
  124.   
  125.          //解析数组参数的构造错误的写法:public Student(String strs[])  
  126.         public void test4()throws Exception{  
  127.             //1、加载类  
  128.             Class cls = Class.forName("cn.csdn.reflect.Student");  
  129.             //2、根据构造器参数类型获取相应的构造器对象     
  130.             Constructor csr = cls.getConstructor(String[].class);  
  131.             String str[]={"111","123"};  
  132.             //3、创建实体对象  
  133.             Student entity = (Student)csr.newInstance(str);  
  134.             //4、调用方法  
  135.             entity.study();  
  136.         }  
  137.     注意:  
  138.         从上面两个程序我们可以发现前的的程序把这个数组做了一 Object 的造型,  
  139.         这是因为按1.5的语法,整个数组是一个参数,而按1.4的语法,数组中的每个  
  140.         元素是一个参数,当把一个字符串传给它时,JDK1.5 会兼容JDK1.4 的语法,  
  141.         即会按1.4的把数组打散成为若干个单独的参数,JAVAC 只把它当成JDK1.4来解析,不把它当过1.5来解释,因此出现参数类型不对问题当我们加上 Object 时,  
  142.         编译器会作特殊处理,编译器不把参数当成数组看,也就不会打散了。       
  143.   
  144.   
  145.   
  146. 但是问题出现了,我们会发现,那个集合类的构造参数没有打印出来,也就是下面的这个构造  
  147.     //带一个集合类型参数的构造  
  148.     private Student(List list){  
  149.         System.out.println(list.size());  
  150.     }  
  151.     这时我们发现这个构造于其它三个不同,是一个私有的构造  
  152.       
  153.     public void test5()throws Exception{  
  154.         //1、加载类  
  155.         Class cls = Class.forName("cn.csdn.reflect.Student");  
  156.         //2、根据构造器参数类型获取相应的构造器对象      
  157. // getDeclaredConstructor()  这个方法是在private 中 使用的   请不要//和public 中//的  getConstructor() 混淆  
  158.         Constructor csr = cls.getDeclaredConstructor(List.class);  
  159. // setAccessible(true) 这个方法是暴力解析  因为他是private 声明的构造方法  
  160.         csr.setAccessible(true);//暴力  
  161.         //3、创建实体对象  
  162.         Student entity = (Student)csr.newInstance(new ArrayList());  
  163.         //4、调用方法  
  164.         entity.study();  
  165.     }  
  166. 3解析里的方法  
  167. 我们开始解析下面这个类里的方法  
  168. public class Student {  
  169.     //无参studay()方法  
  170.     public void studay(){  
  171.         System.out.println("学习中");  
  172.     }  
  173.     //有两个参数的getSum(int a ,int b)方法  
  174.     public int getSum(int a ,int b) {  
  175.         int sum = a + b;  
  176.         return sum;  
  177.     }  
  178.     //静态的主函数  
  179.     public static void main(String[] args) {  
  180.         System.out.println("aaaa");  
  181.     }  
  182. }  
  183. 我们可以通过getMethods()方法反回一个一个Method[] 类型数组,然后遍历输出  
  184. @Test  
  185.     public void Test() throws Exception {  
  186.         Class cls = Class.forName("cn.csdn.reflect.Student");  
  187. //用这个方法时操作类必有一个 无参构造  
  188.         Student stu = (Student) cls.newInstance();  
  189.         Method[] ms = cls.getMethods();  
  190.         for(Method m : ms) {  
  191.             System.out.println(m.toGenericString());  
  192.         }  
  193.     }  
  194. 解析: studay() 这个方法  
  195. @Test  
  196.     public void Test1() throws Exception{  
  197.         Class cls = Class.forName("cn.csdn.reflect.Student");  
  198.         Student stu = (Student) cls.newInstance();  
  199.         Method m = cls.getMethod("studay"null);  
  200.         m.invoke(stu, null);  
  201.     }  
  202. 解析:getSum(int a ,int b)方法  
  203. @Test  
  204.     public void Test2() throws Exception{  
  205.         Class cls = Class.forName("cn.csdn.reflect.Student");//加载类  
  206.         Student stu = (Student) cls.newInstance();// 创建类实例  
  207.         Method m = cls.getMethod("getSum"int.class,int.class);//2解析方法  
  208.         int sum = (Integer) m.invoke(stu, 10,10);//执行方法  
  209.         System.out.println(sum);  
  210.     }  
  211. 解析: 主函数   
  212. @Test  
  213.     public void Test3() throws Exception{  
  214.         Class cls = Class.forName("cn.csdn.reflect.Student");//加载类  
  215.         Student stu = (Student) cls.newInstance();// 创建类实例  
  216.         Method m = cls.getMethod("main", String[].class);//2解析方法  
  217.         m.invoke(stu, (Object)new String[]{"a"});  
  218.     }  
  219. //简便的方法操作方法  
  220.     @Test  
  221.     public void test1()throws Exception{  
  222.         Student st = new Student();  
  223.         //通过构造器 创建 PropertyDescriptor对象  
  224. PropertyDescriptor pd = new PropertyDescriptor("age", Student.class);  
  225.         Method md = pd.getWriteMethod(); //写操作  
  226.         md.invoke(st, 120);  
  227.         System.out.println(st.getAge());  
  228.         md = pd.getReadMethod();  
  229.         int value = (Integer)md.invoke(st, null); //读操作  
  230.         System.out.println(value);  
  231.     }  
  232. 请大家注意这个强制转成Object这个类型,原因和构造方法的原因一样  
  233. 4.解析里面的字段,属性如果一个字段有get方法我们就说这个字段是这个类的属性  
  234. public class Student {  
  235.     private String pub;//属性  
  236.     private String  pvt; //属性  
  237.     private String name;// 字段  
  238.     public String getPub() {  
  239.         return pub;  
  240.     }  
  241.     public String getPvt() {  
  242.         return pvt;  
  243.     }  
  244. }  
  245. 得到所有的字段  
  246. @Test  // 得到所有的字段getDeclaredFields()  
  247.     public void Test5() throws Exception{  
  248.         Class cls = Class.forName("cn.csdn.reflect.Student");  
  249.         Student stu = (Student) cls.newInstance();  
  250.         Field[]  fd = cls.getDeclaredFields();  
  251.         for(Field f : fd) {  
  252.             System.out.println(f.getName());  
  253.             System.out.println(f.toGenericString());  
  254.         }  
  255.     }  
  256. 对属性赋值取值  
  257. @Test  
  258.     public void Test6() throws Exception{  
  259.         Class cls = Class.forName("cn.csdn.reflect.Student");  
  260.         Student stu = (Student) cls.newInstance();  
  261.         Field fd = cls.getDeclaredField("pvt");  
  262.         fd.setAccessible(true);  
  263.         fd.set(stu, "aa");  
  264.         String s = (String)fd.get(stu);  
  265.         System.out.println(s);  
  266.         System.out.println(stu.getPvt());  
  267.     }  
  268.   
  269. 内省(xing)  
  270. Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。  
  271.   
  272. 当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class object  
  273.   
  274. 下面我们通过来操作这个类来解释什么是内省  
  275. public class TestSetGet {  
  276.     private int age;  
  277.     private String name;  
  278.     private String pass;  
  279.     public int getAge() {  
  280.         return age;  
  281.     }  
  282.     public void setAge(int age) {  
  283.         this.age = age;  
  284.     }  
  285.     public String getName() {  
  286.         return name;  
  287.     }  
  288.     public void setName(String name) {  
  289.         this.name = name;  
  290.     }  
  291. }  
  292. /* 
  293. * 通过Introspector类获得Bean对象的 BeanInfo, 然后通过 BeanInfo 来获取属性的描述器( 
  294. * PropertyDescriptor ) 通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法, 
  295. * 然后通过反射机制来调用这些方法。 
  296. */  
  297.     @Test  
  298.     public void test() throws Exception{  
  299.         //得到这个类  
  300.         Class cls = Class.forName("cn.csdn.reflect.TestSetGet");  
  301.         //通过类的newInstance来获取这个类对象  
  302.         TestSetGet tsg = (TestSetGet) cls.newInstance();  
  303.           
  304.         BeanInfo bi = Introspector.getBeanInfo(TestSetGet.class);  
  305.         PropertyDescriptor[] pd = bi.getPropertyDescriptors();  
  306.         for(PropertyDescriptor p : pd) {  
  307.             System.out.println(p.getName());  
  308.             if(p.getName().equals("age")) {  
  309.                 Method m = p.getWriteMethod();  
  310.                 m.invoke(tsg, 12);  
  311.                 System.out.println("aa===   "+p.getPropertyType());  
  312.             }  
  313.         }  
  314.         System.out.println(tsg.getAge());  
  315.     }  
  316.     //简便的方法  
  317.     @Test  
  318.     public void test1()throws Exception{  
  319.         TestSetGet st = new TestSetGet();  
  320.         //通过构造器 创建 PropertyDescriptor对象  
  321. PropertyDescriptor pd = new PropertyDescriptor("age", TestSetGet.class);  
  322.         Method md = pd.getWriteMethod(); //写操作  
  323.         md.invoke(st, 120);  
  324.         System.out.println(st.getAge());  
  325.         md = pd.getReadMethod();  
  326.         int value = (Integer)md.invoke(st, null); //读操作  
  327.         System.out.println(value);  
  328.     }  
分享到:
评论
1 楼 leilei12181218 2015-04-16  
芳姐,我过来溜达溜达,,,嘿嘿。。。

相关推荐

    Spring-IOC手动模拟实现-利用dom4解析xml文件

    通过dom4j解析配置文件,得到list集合(存放Bean标签的id和class属性) * 3.通过反射实例化得到对应的实例化对象,放置在map中(map是键值对,可根据id获取值)(遍历list获取对应的class属性,利用class。formName...

    DWR.xml配置文件说明书(含源码)

    spring beanName 从配置文件中读取的bean的名称 “scope参数允许你配置creator的生命周期,共有以下几个选项:application,session,request,page.这些参数对于用过jsp或servlet的开发人员并不陌生. 3.1 Uing static ...

    spring基础

    按照上面的配置,Spring 将直接采用 Java 反射机制对 Boss 中的 car 和 office 这两个私有成员变量进行自动注入。所以对成员变量使用 @Autowired 后,您大可将它们的 setter 方法(setCar() 和 setOffice())从 Boss...

    springmybatis

    5. 在java 对象和 数据库之间有做mapping 的配置文件,也通常是xml 文件。 mybatis实战教程(mybatis in action)之一:开发环境搭建 mybatis 的开发环境搭建,选择: eclipse j2ee 版本,mysql 5.1 ,jdk 1.7,mybatis...

    Spring.3.x企业应用开发实战(完整版).part2

    3.2.3 Java反射机制 3.3 资源访问利器 3.3.1 资源抽象接口 3.3.2 资源加载 3.4 BeanFactory和ApplicationContext 3.4.1 BeanFactory介绍 3.4.2 ApplicationContext介绍 3.4.3 父子容器 3.5 Bean的生命周期 3.5.1 ...

    Spring3.x企业应用开发实战(完整版) part1

    3.2.3 Java反射机制 3.3 资源访问利器 3.3.1 资源抽象接口 3.3.2 资源加载 3.4 BeanFactory和ApplicationContext 3.4.1 BeanFactory介绍 3.4.2 ApplicationContext介绍 3.4.3 父子容器 3.5 Bean的生命周期 3.5.1 ...

    Spring面试题

    3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。 4. hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。 2. ...

    超级玛丽源码Java-Spring5:春天5

    通过xml配置文件获取类的全路径 再根据反射的Class.forName(全路径)获取类的class文件,再通过class.newInstance()实例化对象 从而实现解耦。 1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂 (1)BeanFactory:...

    java面试题

    53. 描述一下JVM加载class文件的原理机制? 30 54. socket编程 30 54.1. 什么是TCP/IP、UDP? 30 54.2. Socket在哪里呢? 31 54.3. Socket是什么呢? 32 54.4. socket的实现步骤 37 55. Servlet 38 55.1. Servlet工作...

    java面试题库2021.pdf

    ①IoC 与 Bean 配置、 管理 ②AOP 与事务、 权限控制 ③S2SH 整合开发 ④Spring, JPA 整合 2、 Hibernate ①ORM 与持久化映射 ②延迟加载、 性能优化 ③HQL 查询、 条件查询、 SQL 查询 ④二级缓存与查询缓存 3、 ...

    将 Flex 集成到 Java EE 应用程序的最佳实践(完整源代码)

    BlazeDS 将读取 services-config.xml 配置文件,该配置文件又引用了 remoting-config.xml、proxy-config.xml 和 messaging-config.xml 这 3 个配置文件,所以,一共需要 4 个配置文件。 由于 BlazeDS 需要将 Java ...

    +Flex+集成到+Java+EE+应用程序的最佳实践(完整源代码)

    BlazeDS 将读取 services-config.xml 配置文件,该配置文件又引用了 remoting-config.xml、proxy-config.xml 和 messaging-config.xml 这 3 个配置文件,所以,一共需要 4 个配置文件。 由于 BlazeDS 需要将 Java ...

    dwr入门+springmvc实现

    配置dwr组件到dwr.xml文件中,如果有必要,配置convert,进行java和javascript类型互转。 5.通过反射机制,dwr将步骤4的类转换成javascript代码,提供给前台页面调用。 5.编写网页,调用步骤5的javascript中的相关...

    J2EE应用开发详解

    17 2.1 构建开发环境 17 2.1.1 安装JDK 17 2.1.2 安装Tomcat 21 2.1.3 安装Eclipse 23 2.2 配置开发环境 23 2.3 小结 26 第3章 Java的反射机制 27 3.1 Java反射API 27 3.2 加载类的实例 29 3.2.1 加载class对象的两...

    Java学习笔记-个人整理的

    {7.1}Java的文件系统管理}{103}{section.7.1} {7.2}回调模式与FileFilter}{104}{section.7.2} {7.3}\ttfamily RandomAccessFile}{106}{section.7.3} {7.4}基本类型数据序列化}{108}{section.7.4} {7.5}String的...

    整理后java开发全套达内学习笔记(含练习)

    Reflection [java] 反射 [ri'flekʃәn] script n.手写体,小型程序 [skript] serialized vt.序列化,串行化 ['siәriәlaiz]'(serializable adj.)(deserialize反序列化,反串行化) Socket [java] 网络套接字['sɒkit...

    DWR开发包常规客户端服务器端面向对象编程

    基于Spring,在服务器端配置: &lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;!DOCTYPE dwr PUBLIC "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN" "http://getahead.org/dwr//dwr20.dtd"&gt; &lt;dwr&gt; &lt;allow&gt; ...

    SpringFundamentals_injectionExamples

    Spring XML 配置 带有注释的 Spring XML 仅限 Spring 注释 带有自动装配示例的 Spring 注释 对于每个项目,我们包括以下示例: 自动装配 成员变量注入(反射) 二传手注入 构造函数注入 范围示例(单例和原型) ...

    JAVA核心知识点整理(有效)

    25 JAVA8 与元数据.................................................................................................................................25 2.4. 垃圾回收与算法 .................................

Global site tag (gtag.js) - Google Analytics