您的位置:首页 > 编程语言 > Java开发

spring框架的IOC和AOP机制模拟

2012-03-11 00:07 435 查看
从我接触到的两个项目,这两个项目真的很大。但它们的的确确用到了spring进行事务控制,同时其中一个中时整合了struts2和spring。虽然两个框架都是开源的,也是人们所说的轻量级j2ee所使用的组件,但其中的思想却是值得我们学习和使用的。

以下想就spring的IOC(DI)和AOP两个重要的概念通过实践进行理解,以期对spring有一个新的认识。

1、IOC

貌似通常说的DI方式有三种,但其中两种并不常用,对用setter方法的注入倒是使用的很频繁,也可以说是很成熟,那就以这个做为对IOC和理解进行实例演示。

首先来看一下我用作测试的整个工程的目录结构:



1)IOC依赖于一个配置文件beans,这个配置文件也是在服务器启动时就需要加载到内存中的,如果想知道如何在web工程中加载配置文件可以看我博客中《模拟struts架构》描述。beans.xml文件存储于src的根目录。

让我们看下beans文件的内容:

一个简单的xml文件,其中模仿spring的配置文件进行了相关的配置,如果学习过spring的同学应该很容易看懂其中内容,如果没学习过的,那就当作xml来看待就好了,如果xml也不知道,那还是先补一下吧。

[xhtml:nogutter]
view plaincopyprint?

<beans>
<bean id="user" class="com.yyb.model.User" />
<bean id="userDAO" class="com.yyb.dao.impl.UserDAOImpl" />
<bean id="userService" class="com.yyb.service.UserService">
<property name="userDAO" bean="userDAO" />
</bean>
</beans>

[java:nogutter]
view plaincopyprint?

package com.yyb.service;

import com.yyb.dao.UserDAO;

import com.yyb.model.User;

public class UserService

{
private UserDAO userDAO;

void addUser(User u)

{
this.userDAO.save(u);

}
/**
* @return the userDAO
*/
public UserDAO getUserDAO()

{
return userDAO;

}
/**
* @param userDAO
*            the userDAO to set

*/
public void setUserDAO(UserDAO userDAO)

{
this.userDAO = userDAO;

}
}

package com.yyb.service;
import com.yyb.dao.UserDAO;
import com.yyb.model.User;
public class UserService
{
private UserDAO userDAO;
void addUser(User u)
{
this.userDAO.save(u);
}
/**
* @return the userDAO
*/
public UserDAO getUserDAO()
{
return userDAO;
}
/**
* @param userDAO
*            the userDAO to set
*/
public void setUserDAO(UserDAO userDAO)
{
this.userDAO = userDAO;
}
}


将会用作被注入到业务处理类中的类UserDAOImpl.java和它的父类UserDAO.java

[java:nogutter]
view plaincopyprint?

package com.yyb.dao.impl;

import com.yyb.dao.UserDAO;

import com.yyb.model.User;

public class UserDAOImpl implements UserDAO {

@Override

public void save(User u) {

System.out.println("User:" + u.toString());

}
@Override

public void delete() {

System.out.println("delete User");

}
}

[java:nogutter]
view plaincopyprint?

package com.yyb.dao;

import com.yyb.model.User;

public interface UserDAO {

void save(User u);

void delete();

}

package com.yyb.dao;
import com.yyb.model.User;
public interface UserDAO {
void save(User u);
void delete();

}


不要忘记了这个javabean

[java:nogutter]
view plaincopyprint?

package com.yyb.model;

public class User

{
private String userName;

private String password;

/**
* @return the userName

*/
public String getUserName()

{
return userName;

}
/**
* @param userName
* the userName to set

*/
public void setUserName(String userName)

{
this.userName = userName;

}
/**
* @return the password
*/
public String getPassword()

{
return password;

}
/**
* @param password

* the password to set

*/
public void setPassword(String password)

{
this.password = password;

}
public String toString()

{
StringBuffer sb = new StringBuffer();

sb.append(this.userName);

sb.append(this.password);

return sb.toString();

}
}

[java:nogutter]
view plaincopyprint?

package com.yyb.spring;

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.jdom.Document;

import org.jdom.Element;

import org.jdom.JDOMException;

import org.jdom.input.SAXBuilder;

public class ClassPathXmlApplicationContext implements BeanFactory

{
private Map<String, Object> beans = new HashMap<String, Object>();

public ClassPathXmlApplicationContext() throws JDOMException, IOException,

InstantiationException, IllegalAccessException,
ClassNotFoundException, SecurityException, NoSuchMethodException,

IllegalArgumentException, InvocationTargetException

{
SAXBuilder sb = new SAXBuilder();

// 构造文档对象

Document doc = sb.build(ClassPathXmlApplicationContext.class

.getClassLoader().getResourceAsStream("beans.xml"));

// 获取根元素
Element root = doc.getRootElement();
// 取到根元素所有元素

List list = root.getChildren();

for (int i = 0; i < list.size(); i++)

{
Element element = (Element) list.get(i);

// 取id子元素

String beanid = element.getAttributeValue("id");

// 取class子元素

String clzss = element.getAttributeValue("class");

// 实例化
Object o = Class.forName(clzss).newInstance();

// 将所有bean放入map中

beans.put(beanid, o);
// 获取property 进行依赖注入

for (Element propertyElement : (List<Element>) element

.getChildren("property"))

{
String name = propertyElement.getAttributeValue("name");

String bean = propertyElement.getAttributeValue("bean");

// 从beans.xml中根据id取到类的对象

Object beanObj = this.getBean(name);

// 形成setXXX方法名

String methodName = "set" + name.substring(0, 1).toUpperCase()

+ name.substring(1);

// 反射机制对方法进行调用,将对象在加载bean时就注入到环境上下文中

Method m = o.getClass().getMethod(methodName,
beanObj.getClass().getInterfaces()[0]);

// 执行注入,相当于执行了一个setXXX(args..)的方法

m.invoke(o, beanObj);
}
}
}
@Override

public Object getBean(String name)

{
return beans.get(name);

}
}

package com.yyb.spring;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
public class ClassPathXmlApplicationContext implements BeanFactory
{
private Map<String, Object> beans = new HashMap<String, Object>();
public ClassPathXmlApplicationContext() throws JDOMException, IOException,
InstantiationException, IllegalAccessException,
ClassNotFoundException, SecurityException, NoSuchMethodException,
IllegalArgumentException, InvocationTargetException
{
SAXBuilder sb = new SAXBuilder();
// 构造文档对象
Document doc = sb.build(ClassPathXmlApplicationContext.class
.getClassLoader().getResourceAsStream("beans.xml"));
// 获取根元素
Element root = doc.getRootElement();
// 取到根元素所有元素
List list = root.getChildren();

for (int i = 0; i < list.size(); i++)
{
Element element = (Element) list.get(i);
// 取id子元素
String beanid = element.getAttributeValue("id");
// 取class子元素
String clzss = element.getAttributeValue("class");
// 实例化
Object o = Class.forName(clzss).newInstance();
// 将所有bean放入map中
beans.put(beanid, o);
// 获取property 进行依赖注入
for (Element propertyElement : (List<Element>) element
.getChildren("property"))
{
String name = propertyElement.getAttributeValue("name");
String bean = propertyElement.getAttributeValue("bean");
// 从beans.xml中根据id取到类的对象
Object beanObj = this.getBean(name);
// 形成setXXX方法名
String methodName = "set" + name.substring(0, 1).toUpperCase()
+ name.substring(1);
// 反射机制对方法进行调用,将对象在加载bean时就注入到环境上下文中
Method m = o.getClass().getMethod(methodName,
beanObj.getClass().getInterfaces()[0]);
// 执行注入,相当于执行了一个setXXX(args..)的方法
m.invoke(o, beanObj);
}
}
}
@Override
public Object getBean(String name)
{
return beans.get(name);
}
}


[java:nogutter]
view plaincopyprint?

package com.yyb.spring;

public interface BeanFactory {

Object getBean(String name);
}

[java:nogutter]
view plaincopyprint?

package com.yyb.service;

import java.io.IOException;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Proxy;

import org.jdom.JDOMException;

import org.junit.Test;

import com.yyb.aop.LogInterceptor;

import com.yyb.dao.UserDAO;

import com.yyb.dao.impl.UserDAOImpl;

import com.yyb.model.User;

import com.yyb.spring.BeanFactory;

import com.yyb.spring.ClassPathXmlApplicationContext;

public class UserServieTest {

@Test
public void testAddUser() throws JDOMException, IOException,

InstantiationException, IllegalAccessException,
ClassNotFoundException, SecurityException,

IllegalArgumentException, NoSuchMethodException,
InvocationTargetException {
BeanFactory factory = new ClassPathXmlApplicationContext();

UserService userService = (UserService) factory.getBean("userService");

User u = new User();

u.setUserName("yyb");

u.setPassword("1234");

userService.addUser(u);
}

}

package com.yyb.service;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import org.jdom.JDOMException;
import org.junit.Test;
import com.yyb.aop.LogInterceptor;
import com.yyb.dao.UserDAO;
import com.yyb.dao.impl.UserDAOImpl;
import com.yyb.model.User;
import com.yyb.spring.BeanFactory;
import com.yyb.spring.ClassPathXmlApplicationContext;
public class UserServieTest {
@Test
public void testAddUser() throws JDOMException, IOException,
InstantiationException, IllegalAccessException,
ClassNotFoundException, SecurityException,
IllegalArgumentException, NoSuchMethodException,
InvocationTargetException {
BeanFactory factory = new ClassPathXmlApplicationContext();
UserService userService = (UserService) factory.getBean("userService");
User u = new User();
u.setUserName("yyb");
u.setPassword("1234");
userService.addUser(u);
}

}


2、AOP

这一个概念不需要在实践的过程就应该能理解,其实就是在我们的业务流程中(这个流程打个比方是一条直线),然后我们在第1厘米和第10厘米处分别打了两个记号,这样你的流程就不得不经过我们的记号再住下执行。这就是AOP(切面)的大致理解。

所以可以这样说,我们如果要是想在执行一个方法的前面和后面都加入日志打印,那我们的通常想法是再写两个方法,一个在调用原来的方法前调用 ,一个在执行后调用 ,这样也是AOP的现实例子。那我们又应该如何来模拟呢,我们还是以这个记日志的例子为例来模拟,如果这个成功了那就可以改为事务的处理。那不就是我们常用的AOP的最好实践么。

再提示一上,设计模式中有一种模式叫做代理,而我们想的是让程序根据要执行的方法而打印出不同的日志,那你会想到什么,动态代理。对,我们就是想用动态代理来模拟AOP。

知道了这一利害,那就直接让我们看代码吧:

类中的invoke方法是必须要有这,在invoke方法中我们调用了beforeMethod方法,这个就打印出了方法执行前的日志,然后执行真正要执行的方法。这里没有调用类似afterMethod这样的方法,因为原理都是一样的。

这样就真的将我的想要组合在一起的两方法捆绑好了。那如何才能让他们一起执行呢。

[java:nogutter]
view plaincopyprint?

package com.yyb.aop;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class LogInterceptor implements InvocationHandler {

private Object target;

public void beforeMethod(Method m) {

System.out.println("before "+m.getName()+"method start");

}
@Override

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

beforeMethod(method);
method.invoke(target, args);
return null;

}
/**
* @return the target

*/
public Object getTarget() {

return target;

}
/**
* @param target the target to set

*/
public void setTarget(Object target) {

this.target = target;

}
}

[java:nogutter]
view plaincopyprint?

package com.yyb.service;

import java.lang.reflect.Proxy;

import org.junit.Test;

import com.yyb.aop.LogInterceptor;

import com.yyb.dao.UserDAO;

import com.yyb.dao.impl.UserDAOImpl;

import com.yyb.model.User;

public class UserServieTest {

@Test

public void testProxy() {

UserDAO userDAO = new UserDAOImpl();

LogInterceptor log = new LogInterceptor();

log.setTarget(userDAO);
UserDAO userProxy = (UserDAO) Proxy.newProxyInstance(UserDAO.class

.getClassLoader(), new Class[] { UserDAO.class }, log);

User u = new User();

userProxy.save(u);
userProxy.delete();
}
}

package com.yyb.service;
import java.lang.reflect.Proxy;
import org.junit.Test;
import com.yyb.aop.LogInterceptor;
import com.yyb.dao.UserDAO;
import com.yyb.dao.impl.UserDAOImpl;
import com.yyb.model.User;

public class UserServieTest {

@Test
public void testProxy() {
UserDAO userDAO = new UserDAOImpl();
LogInterceptor log = new LogInterceptor();
log.setTarget(userDAO);
UserDAO userProxy = (UserDAO) Proxy.newProxyInstance(UserDAO.class
.getClassLoader(), new Class[] { UserDAO.class }, log);

User u = new User();
userProxy.save(u);
userProxy.delete();
}
}


总结:

spring的这两个机制不管是在实际运用中还是面试中都需要我们深入的了解,那样才会事半功倍。我希望我们通过实践对这两个概念也好机制也好都有新的理解才是最好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: