IOC模式与JAVA反射机制

来源:互联网 发布:淘宝名字大全霸气 编辑:程序博客网 时间:2024/06/16 04:16

在Java中反射和动态代理机制很强大,通过反射机制在运行时获取信息。用于实现IOC。

代理是Java基本的设计模式,提供向对象插入额外的或不同的操作。Java的动态代理能动态的创建代理对象,以及动态的调用代理方法。用于实现AOP。
一、Java反射机制
1、作用
(1)在运行时判断任意一个对象所属的类;
(2)在运行时获取类的对象;
(3)在运行时获得类所具有的成员变量和方法等;
2、Reflection类:
package com.makocn.reflection;
import java.lang.reflect.Method;
import java.util.Hashtable;

public class Reflection {
 public static void main(String[] args) throws Exception {
  Reflection reflection = new Reflection();
  reflection.getNameTest();
  System.out.println("*****************************************");
  reflection.getMethodTest();
 }
 public void getNameTest() throws Exception {
  String name = "马可中国";
  Class cls = name.getClass();
  System.out.println("String类名: " + cls.getName());
  Class superBtnClass = cls.getSuperclass();
  System.out.println("String的父类名: " + superBtnClass.getName());
  Class clsTest = Class.forName("java.util.Date");
  System.out.println("clsTest name: " + clsTest.getName());
 }
 public void getMethodTest() throws Exception {
  Class cls = Class.forName("com.makocn.reflection.Reflection");
  Class ptypes[] = new Class[2];
  ptypes[0] = Class.forName("java.lang.String");
  ptypes[1] = Class.forName("java.util.Hashtable");
  Method method = cls.getMethod("testMethod", ptypes);
  Object args[] = new Object[2];
  args[0] = "oh, my dear!";
  Hashtable<String, String> ht = new Hashtable<String, String>();
  ht.put("name", "马可中国");
  args[1] = ht;
  String returnStr = (String) method.invoke(new Reflection(), args);
  System.out.println("returnStr= " + returnStr);
 }
 public String testMethod(String str, Hashtable ht) throws Exception {
  String returnStr = "返回值";
  System.out.println("测试testMethod()方法调用");
  System.out.println("str= " + str);
  System.out.println("名字= " + (String) ht.get("name"));
  System.out.println("结束testMethod()方法调用");
  return returnStr;
 }
}
3、运行结果:
String类名: java.lang.String
String的父类名: java.lang.Object
clsTest name: java.util.Date
*****************************************
测试testMethod()方法调用
str= oh, my dear!
名字= 马可中国
结束testMethod()方法调用
returnStr= 返回值
二、Java耦合例子
1、Chinese类:
package com.makocn.reflection;
public class Chinese{
 public void sayHello(String name) {
  String helloWorld = "你好," + name;
  System.out.println(helloWorld);
 }
}
2、American类
package com.makocn.reflection;
public class American{
 public void sayHello(String name) {
   String helloWorld = "Hello," + name;
  System.out.println(helloWorld);
 }
}
3、HelloWorld类:
package com.makocn.reflection;
public class HelloWorld {
 public static void main(String[] args) {
  Chinese chinese = new Chinese();
  chinese.sayHello("马可中国");
  American american = new American();
  american.sayHello("makocn");
 }
}
从HelloWorld可以看到,该类与Chinese.java类和American.java类都存在强耦合关系。
4、运行结果:
你好,马可中国
Hello,makocn
三、工厂模式解耦例子
1、Human接口:
package com.makocn.reflection;
public interface Human {
  public void sayHello(String name);
}
2、Chinese类:
package com.makocn.reflection;
public class Chinese implements Human{
 public void sayHello(String name) {
  String helloWorld = "你好," + name;
  System.out.println(helloWorld);
 }
}
3、American类:
package com.makocn.reflection;
public class American implements Human{
 public void sayHello(String name) {
   String helloWorld = "Hello," + name;
  System.out.println(helloWorld);
 }
}
4、HumanFactory工厂类:
package com.makocn.reflection;
public class HumanFactory {
 public Human getHuman(String type) {
  if ("chinese".equals(type)) {
   return new Chinese();
  } else {
   return new American();
  }
 }
}
5、HelloWorld类:
package com.makocn.reflection;
public class HelloWorld {
 public static void main(String[] args) {
  HumanFactory factory = new HumanFactory();
         Human human1 = factory.getHuman("chinese");
         human1.sayHello("马可中国");       
         Human human2 = factory.getHuman("american");
         human2.sayHello("makocn");
 }
}
6、运行结果:
你好,马可中国
Hello,makocn
利用工厂HumanFactory,我们不再与具体的实现类Chinese和American存在耦合关系,而只是与接口类Human存在耦合关系,具体对象的获取只是通过传入字符串来获取,降低了类与类之间的耦合性。但如果我们要换具体类的实现时,则我们还需修改工厂类中的字符串。
四、IOC实现
IOC(Inverse of Control)翻译为控制反转,也称DI(Dependence Injection)依赖注入。实现好莱坞原则:不用你主动来找我,我会通知你。
通过IOC可以将实现类、参数信息等配置在其对应的配置文件中,当需要更改实现类或参数信息时,只需要修改配置文件即可,进一步降低了类与类之间的耦合。同时还可以对某对象所需要的其它对象进行注入。
Spring的IOC的实现原理就是Java反射机制, 同时Spring还充当了工厂角色,Spring的工厂类读取配置文件、利用反射机制注入对象等。程序可通过bean的名称获取对应的对象。
1、BeanFactory工厂类
package com.makocn.reflection;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class BeanFactory {
 private Map<String, Object> beanMap = new HashMap<String, Object>();
 public void init(String xml) {
  try {
   // 读取指定的配置文件
   SAXReader reader = new SAXReader();
   ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
   // 从class目录下获取指定的xml文件
   InputStream ins = classLoader.getResourceAsStream(xml);
   Document doc = reader.read(ins);
   Element root = doc.getRootElement();
   Element foo;
   // 遍历bean
   for (Iterator i = root.elementIterator("bean"); i.hasNext();) {
    foo = (Element) i.next();
    // 获取bean的属性id和class
    Attribute id = foo.attribute("id");
    Attribute cls = foo.attribute("class");
    // 利用Java反射机制,通过class的名称获取Class对象
    Class bean = Class.forName(cls.getText());
    // 获取对应class的信息
    java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);
    // 获取其属性描述
    java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();
    // 设置值的方法
    Method mSet = null;
    // 创建一个对象
    Object obj = bean.newInstance();
    // 遍历该bean的property属性
    for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) {
     Element foo2 = (Element) ite.next();
     // 获取该property的name属性
     Attribute name = foo2.attribute("name");
     String value = null;
     // 获取该property的子元素value的值
     for (Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) {
      Element node = (Element) ite1.next();
      value = node.getText();
      break;
     }
     for (int k = 0; k < pd.length; k++) {
      if (pd[k].getName().equalsIgnoreCase(name.getText())) {
       mSet = pd[k].getWriteMethod();
       // 利用Java的反射极致调用对象的某个set方法,并将值设置进去
       mSet.invoke(obj, value);
      }
     }
    }
    // 将对象放入beanMap中,其中key为id值,value为对象
    beanMap.put(id.getText(), obj);
   }
  } catch (Exception e) {
   System.out.println(e.toString());
  }
 }
 public Object getBean(String beanName) {
  Object obj = beanMap.get(beanName);
  return obj;
 }
 public static void main(String[] args) {
  BeanFactory factory = new BeanFactory();
  factory.init("config.xml");
  JavaBean javaBean = (JavaBean) factory.getBean("javaBean");
  System.out.println("userName=" + javaBean.getUserName());
  System.out.println("password=" + javaBean.getPassword());
 }
}
2、JavaBean类:
package com.makocn.reflection;
public class JavaBean {
 private String userName;
 private String password;
 public String getPassword() {
  return password;
 }
 public String getUserName() {
  return userName;
 }
 public void setUserName(String userName) {
  this.userName = userName;
 }
 public void setPassword(String password) {
  this.password = password;
 }
}
3、config.xml配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans>
 <bean id="javaBean" class="com.makocn.reflection.JavaBean">
  <property name="userName">
   <value>马可中国</value>
  </property>
  <property name="password">
   <value>1357908642abc</value>
  </property>
 </bean>
</beans>
4、运行结果:
userName=马可中国
password=1357908642abc
虽然在main()方法中没有对属性赋值,但属性值已经被注入。
在BeanFactory类中:
Class bean = Class.forName(cls.getText());通过类名来获取对应的类;
mSet.invoke(obj, value);通过invoke方法来调用特定对象的特定方法;
实现的原理都是基于Java的反射机制。
这只是对IOC的一个简单演示,Spring要复杂得多;如一个bean引用另一个bean,可有多个配置文件,通过多种方式载入配置文件等。

0 0
原创粉丝点击