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>
将会用作被注入到业务处理类中的类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");
}
}
不要忘记了这个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;
public interface BeanFactory {
Object getBean(String name);
}
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;
}
}
总结:
spring的这两个机制不管是在实际运用中还是面试中都需要我们深入的了解,那样才会事半功倍。我希望我们通过实践对这两个概念也好机制也好都有新的理解才是最好。
以下想就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的这两个机制不管是在实际运用中还是面试中都需要我们深入的了解,那样才会事半功倍。我希望我们通过实践对这两个概念也好机制也好都有新的理解才是最好。
相关文章推荐
- 模拟SSH之--spring框架的IOC和AOP机制模拟
- Spring框架原理(一)-- IOC与AOP
- 自己实现的一个简易Spring框架(IoC+AOP)
- Spring AOP实现机制(二)--ProxyFactoryBean---将Spring AOP和Spring IoC容器相结合
- 结合依赖注入与AOP简单模拟实现Spring框架 推荐
- (精简)Spring框架的IoC(替代工厂类实现方法)和AOP(定义规则,约定大于配置)
- Spring框架IOC和AOP的实现原理
- Spring框架IOC和AOP的理解
- Spring框架IOC容器和AOP解析
- bboss aop ioc机制配置
- Spring框架的IoC和AOP
- 【Java】模拟Sping,实现其IOC和AOP核心(一)
- Spring框架 之 反射机制简单实现基于XML标签的IOC与DI
- spring框架的ioc和aop通俗解释
- spring框架学习之路(一)-入门基础(3)-IOC和AOP的综合应用
- 又一次闲来无聊,使用Java的动态代理机制来模拟AOP
- Spring框架IOC容器和AOP解析
- Spring框架的 IoC和AOP
- spring框架的ioc和aop通俗解释
- 模拟实现Struts拦截器-蕴含着代理模式,AOP,工厂模式,依赖注入,Java 反射,动态构造等机制