一、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,實現起來更復雜。這里只是淺析,有助于理解吧。