一、Spring IOC
为使用Spring IoC容器,应用代码可以通过下面两个接口完成:
1.BeanFactory。当应用创建BeanFactory实例时,实际上是完成了JavaBean的实例化、配置以及管理。
Resource resource = new ClassPathResource("appcontext.xml");
BeanFactory factory = new XmlBeanFactory(resource);
HelloWord hw = (HelloWorld)factory.getBean("fileHelloWorld");
appcontext.xml的部分内容如下示例:
1 <beans>
2 <bean name="hello" class="com.taiji.HelloWorld">
3 <property name='hello'>
4 <value>I love you!</value>
5 </property>
6 <property name='person'>
7 <ref bean="person" />
8 </property
9 </bean>
10 <bean name="person">
11 <property name='name'>
12 <value>Liu</value>
13 </property>
14 <property name='age'>
15 <value>25</value>
16 </property
17 </bean>
18 </beans>
2.ApplicationContext。继承于BeanFactory,主要用于J2EE开发,也是Spring推荐使用的接口。对于Web应用而
言,当J2EE Web应用部署并启动时,Spring
ApplicationContext将会自动被实例化。通过ContextLoaderServlet和ContextLoaderListener能
够自动创建ApplicationContext实例,开发者也可以手动创建。对于struts,采用PlugIn的方式加载是一个非常好的方式。见前面
的struts和spring的整合方案。
那么Spring是怎么做到IOC的呢?Java的反射即可实现IOC机制,通过反射可以生成对象实例,并且通过调用其set方法设置对象的属性:
public static Object newInstance(String className) {
Class<?> cls = null;
Object obj = null;
try {
cls = Class.forName(className);
obj = cls.newInstance();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
return obj;
}
public static void setProperty(Object obj, String name, String value) {
Class<? extends Object> clazz = obj.getClass();
try {
String methodName = returnSetMthodName(name);
Method[] ms = clazz.getMethods();
for (Method m : ms) {
if (m.getName().equals(methodName)) {
if (m.getParameterTypes().length == 1) {
Class<?> clazzParameterType = m.getParameterTypes()[0];
setFieldValue(clazzParameterType.getName(), value, m,
obj);
break;
}
}
}
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
IOC不难吧,你也可以做一个IOC框架哦?
二、Spring AOP
Spring的AOP要复杂一些,不是仅仅搞个反射就能解决的。AOP最简单的实现机制就是JAVA的动态代理。
动态代理在调用真正的业务类方法之前或之后都插入了代码,这就是JDK的动态代理做的事情,如下是一个动态代理的例子:
public interface Action {
void method();
}
public class ActionImpl implements Action
{
public void mothod() {
System.out.println("Action!");
}
}
public class MyInvocationHandler implements InvocationHandler {
private Object obj;
public MyInvocationHandler(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("Before Action");
Object returnObject = method.invoke(obj, args);
System.out.println("After Action.");
return returnObject;
public static void main(String[] args) throws InterruptedException,
IllegalArgumentException, SecurityException,
InstantiationException, IllegalAccessException,
InvocationTargetException, NoSuchMethodException {
//实现业务逻辑的类
ActionImpl a = new ActionImpl();
//JDK创建的动态逻辑类,调用上面的构造函数注入
MyInvocationHandler myInvocation = new MyInvocationHandler(a);
//建业务逻辑类的动态代理类
Object proxy = Proxy.newProxyInstance(ActionImpl.class.getClassLoader(),
ActionImpl.class.getInterfaces(), myInvocation);
//业务类自己调用运行代理对象
Action action = (Action) proxy;
action.method();
}
}
运行后会打印出:
Before Action.
Action!
After Action.
Java的动态代理有一个缺陷,它代理的类必须有一个接口类,否则就不能实现动态代理。在面向接口的编程里面,也许不会有问题,但是事情总是有特殊,那如何实现呢?在Spring中是通过CGLIB来实现的。CGLIB可以直接对类进行增强。如下代码对一个类进行增强:
public class MyClass {
public void method() {
System.out.println("MyClass.method()");
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.MethodInterceptor;
public class Main {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyClass.class);
enhancer.setCallback( new MethodInterceptorImpl() );
MyClass my = (MyClass)enhancer.create();
my.method();
}
}
class MethodInterceptorImpl implements MethodInterceptor {
public Object intercept(Object obj,
Method method,
Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println(method);
proxy.invokeSuper(obj, args);
return null;
}
}
执行结果:
public void MyClass.method()
MyClass.method()
可以看到通过CGLIB实现类方法的增加并不比动态代理复杂。当然Spring中需要考虑的东西更多,具体可以研究org.springframework.aop.framework.Cglib2AopProxy.java,实现起来更复杂。这里只是浅析,有助于理解吧。