在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;
//
创建一个对象