Spring IOC、DI、AOP原理和实现

(1)Spring IOC原理

         IOC的意思是控件反转也就是由容器控制程序之间的关系,把控件权交给了外部容器,之前的写法,由程序代码直接操控,而现在控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。网上有一个很形象的比喻:

我们是如何找女朋友的?常见的情况是,我们到处去看哪里有长得漂亮身材又好的mm,然后打听她们的兴趣爱好、qq号、电话号、ip号、iq号………,想办法认识她们,
投其所好送其所要,然后嘿嘿……这个过程是复杂深奥的,我们必须自己设计和面对每个环节。传统的程序开发也是如此,在一个对象中,如果要使用另外的对象,
就必须得到它(自己new一个,或者从JNDI中查询一个),使用完之后还要将对象销毁(比如Connection等),对象始终会和其他的接口或类藕合起来。
  那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,
告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,
我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的
机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,
把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,
而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

 (2)DI(Dependency Injection,依赖注入)
        IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,
依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 
spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。
在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系
的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。


下面来模拟下IOC和DI的实现原理。
项目的结构图如下:
1、首先定义DAO接口和接口的实现类
  1. package com.dao;  
  2.   
  3. public interface PersonDAO {  
  4.     public void save();  
  5. }  
  1. package com.dao.impl;  
  2.   
  3. import com.dao.PersonDAO;  
  4.   
  5. public class PersonDaoImpl implements PersonDAO {  
  6.   
  7.     @Override  
  8.     public void save() {  
  9.         System.out.println("保存");  
  10.     }  
  11.   
  12. }  
2、创建一个Junit测试类
  1. package com.test;  
  2.   
  3. import org.junit.Test;  
  4. import org.springframework.context.ApplicationContext;  
  5. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  6.   
  7. import com.dao.PersonDAO;  
  8. import com.myUtil.MyClassPathXmlApplicationContext;  
  9. import com.service.PersonService;  
  10.   
  11.   
  12. public class PersonTest {  
  13.       
  14.     @Test  
  15.     public void instanceSpring1(){  
  16.         /** 
  17.          *  
  18.          * spring 的实现 
  19.          */  
  20.         //IOC  
  21.         ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");  
  22.         PersonDAO pd = (PersonDAO) ac.getBean("personDAO");  
  23.         pd.save();  
  24.         //DI  
  25.         PersonService ps = (PersonService) ac.getBean("personService");  
  26.         ps.save();  
  27.     }  
  28.       
  29.     @Test  
  30.     public void instanceSpring2(){  
  31.           
  32.         /** 
  33.          * 我的实现 
  34.          *  
  35.          */  
  36.         MyClassPathXmlApplicationContext mac = new MyClassPathXmlApplicationContext("beans.xml");  
  37.         PersonDAO mpd = (PersonDAO) mac.getBean("personDAO");  
  38.         mpd.save();  
  39.         //DI  
  40.         PersonService ps = (PersonService) mac.getBean("personService");  
  41.         ps.save();  
  42.     }  
  43.       
  44. }  
方法instanceSpring1为Spring中的实现用到ClassPathXmlApplicationContext类,要实现IOC的原理要定义自己 的MyClassPathXmlApplicationContext首先读出beans.xml中的配置信息,通过反射机制实现bean,最后注入所需要的 bean。
  1. package com.myUtil;  
  2. import java.beans.Introspector;  
  3. import java.beans.PropertyDescriptor;  
  4. import java.lang.reflect.Method;  
  5. import java.net.URL;  
  6. import java.util.ArrayList;  
  7. import java.util.HashMap;  
  8. import java.util.List;  
  9. import java.util.Map;  
  10. import org.dom4j.Document;  
  11. import org.dom4j.Element;  
  12. import org.dom4j.io.SAXReader;  
  13.   
  14. public class MyClassPathXmlApplicationContext {  
  15.     // xml所有的属性  
  16.     private ArrayList<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();  
  17.     // xml中所有的bean  
  18.     private Map<String, Object> sigletons = new HashMap<String, Object>();  
  19.   
  20.     public MyClassPathXmlApplicationContext(String file) {  
  21.         readXml(file);  
  22.         instanceBeans();  
  23.         instanceObject();  
  24.     }  
  25.   
  26.     /** 
  27.      * 注入 
  28.      */  
  29.     private void instanceObject() {  
  30.         for (BeanDefinition beanDefinition : beanDefinitions) {  
  31.             //判断有没有注入属性  
  32.             if (beanDefinition.getProperty() != null) {  
  33.                 Object bean = sigletons.get(beanDefinition.getId());  
  34.                 if (bean != null) {  
  35.                     try {  
  36.                         //得到被注入bean的所有的属性  
  37.                         PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();  
  38.                         //得到所有的注入bean属性  
  39.                         for(PropertyDefinition propertyDefinition:beanDefinition.getProperty()){  
  40.                             for(PropertyDescriptor propertyDescriptor:ps){  
  41.                                 if(propertyDescriptor.getName().equals(propertyDefinition.getName())){  
  42.                                     Method setter = propertyDescriptor.getWriteMethod();//获取set方法  
  43.                                     if(setter!=null){  
  44.                                         setter.setAccessible(true);//得到private权限  
  45.                                         //注入属性  
  46.                                         setter.invoke(bean, sigletons.get(propertyDefinition.getRef()));  
  47.                                     }  
  48.                                     break;  
  49.                                 }  
  50.                             }  
  51.                         }  
  52.                     } catch (Exception e) {  
  53.                         // TODO Auto-generated catch block  
  54.                         e.printStackTrace();  
  55.                     }  
  56.                 }  
  57.             }  
  58.         }  
  59.     }  
  60.   
  61.     /** 
  62.      * 实例所有的bean 
  63.      */  
  64.     private void instanceBeans() {  
  65.         for (int i = 0; i < beanDefinitions.size(); i++) {  
  66.             BeanDefinition bd = beanDefinitions.get(i);  
  67.             try {  
  68.                 try {  
  69.                     if (bd.getClassName() != null  
  70.                             && !bd.getClassName().equals(""))  
  71.                         sigletons.put(bd.getId(), Class.forName(  
  72.                                 bd.getClassName()).newInstance());  
  73.                 } catch (InstantiationException e) {  
  74.                     // TODO Auto-generated catch block  
  75.                     e.printStackTrace();  
  76.                 } catch (IllegalAccessException e) {  
  77.                     // TODO Auto-generated catch block  
  78.                     e.printStackTrace();  
  79.                 }  
  80.             } catch (ClassNotFoundException e) {  
  81.                 // TODO Auto-generated catch block  
  82.                 e.printStackTrace();  
  83.             }  
  84.         }  
  85.     }  
  86.   
  87.     /** 
  88.      * 读xml 
  89.      *  
  90.      * @param file 
  91.      */  
  92.     private void readXml(String file) {  
  93.         try {  
  94.             SAXReader reader = new SAXReader(); // 使用SAX方式解析XML  
  95.             URL xmlPath = this.getClass().getClassLoader().getResource(file);  
  96.             Document doc = reader.read(xmlPath);  
  97.             Element root = doc.getRootElement(); // 取得根节点  
  98.             List<Element> beans = root.elements();  
  99.             for (Element element : beans) {  
  100.                 String id = element.attributeValue("id");// id;  
  101.                 String clazz = element.attributeValue("class");  
  102.                 BeanDefinition bd = new BeanDefinition(id, clazz);  
  103.                 // 读取子元素  
  104.                 if (element.hasContent()) {  
  105.                     List<Element> propertys = element.elements();  
  106.                     for (Element property : propertys) {  
  107.                         String name = property.attributeValue("name");  
  108.                         String ref = property.attributeValue("ref");  
  109.                         PropertyDefinition pd = new PropertyDefinition(name,  
  110.                                 ref);  
  111.                         bd.getProperty().add(pd);  
  112.                     }  
  113.                 }  
  114.                 beanDefinitions.add(bd);  
  115.             }  
  116.         } catch (Exception e) {  
  117.             // TODO: handle exception  
  118.         }  
  119.     }  
  120.   
  121.     /** 
  122.      * 通过名字得到bean 
  123.      *  
  124.      * @param str 
  125.      * @return 
  126.      */  
  127.     public Object getBean(String str) {  
  128.         return sigletons.get(str);  
  129.     }  
  130.   
  131. }  
读取所的bean实体
  1. package com.myUtil;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class BeanDefinition {  
  7.     private String id;  
  8.     private String className;  
  9.     private List<PropertyDefinition> property = new ArrayList<PropertyDefinition>();  
  10.   
  11.     public BeanDefinition(String id, String className) {  
  12.         super();  
  13.         this.id = id;  
  14.         this.className = className;  
  15.     }  
  16.   
  17.     public String getId() {  
  18.         return id;  
  19.     }  
  20.   
  21.     public void setId(String id) {  
  22.         this.id = id;  
  23.     }  
  24.   
  25.     public String getClassName() {  
  26.         return className;  
  27.     }  
  28.   
  29.     public void setClassName(String className) {  
  30.         this.className = className;  
  31.     }  
  32.   
  33.     public List<PropertyDefinition> getProperty() {  
  34.         return property;  
  35.     }  
  36.   
  37.     public void setProperty(List<PropertyDefinition> property) {  
  38.         this.property = property;  
  39.     }  
  40.   
  41. }  
注入属性实体
  1. package com.myUtil;  
  2.   
  3. public class PropertyDefinition {  
  4.     private String name;  
  5.     private String ref;  
  6.   
  7.     public PropertyDefinition(String name, String ref) {  
  8.         this.name = name;  
  9.         this.ref = ref;  
  10.     }  
  11.   
  12.     public String getName() {  
  13.         return name;  
  14.     }  
  15.   
  16.     public void setName(String name) {  
  17.         this.name = name;  
  18.     }  
  19.   
  20.     public String getRef() {  
  21.         return ref;  
  22.     }  
  23.   
  24.     public void setRef(String ref) {  
  25.         this.ref = ref;  
  26.     }  
  27.   
  28. }  
业务接口和实现类
  1. package com.service;  
  2.   
  3. public interface PersonService {  
  4.     public void save();  
  5. }  
  1. package com.service.impl;  
  2.   
  3. import com.dao.PersonDAO;  
  4. import com.service.PersonService;  
  5.   
  6. public class PersonServiceImpl implements PersonService{  
  7.     private PersonDAO pdo;  
  8.   
  9.     public PersonDAO getPdo() {  
  10.         return pdo;  
  11.     }  
  12.   
  13.     public void setPdo(PersonDAO pdo) {  
  14.         this.pdo = pdo;  
  15.     }  
  16.   
  17.     @Override  
  18.     public void save() {  
  19.         pdo.save();  
  20.     }  
  21.       
  22. }  
beans.xml配置
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  
  6.             
  7.     <bean id="personDAO" class="com.dao.impl.PersonDaoImpl"></bean>  
  8.     <bean id="personService" class="com.service.impl.PersonServiceImpl">  
  9.         <property name="pdo" ref="personDAO"></property>  
  10.     </bean>  
  11. </beans>  

(3)AOP面向切面

    AOP是OOP的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面编程。要理解AOP首先得弄明白代理的概念。对于代理看下点击打开链接这篇文章。

  AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等。 AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中"临时"生成 AOP 动态代理类,因此也被称为运行时增强。

知道这些其他的就是些配置了。

简单的实现annotations和xml对AOP的实现。

首先看下目录结构

MyInterceptor、MyInterceptor2分别是以annotations和xml定义的切面类

[java] view plaincopy
  1. package com.service;  
  2.   
  3. import org.aspectj.lang.annotation.Aspect;  
  4. import org.aspectj.lang.annotation.Before;  
  5. import org.aspectj.lang.annotation.Pointcut;  
  6.   
  7. @Aspect  
  8. public class MyInterceptor {  
  9.     @Pointcut("execution (* com.serviceImpl.PersonServiceImpl.*(..))")  
  10.     private void myMethod(){};  
  11.       
  12.     @Before("myMethod()")  
  13.     public void doAccessCheck(){  
  14.         System.out.println("before");  
  15.     }  
  16.       
  17. }  

[java] view plaincopy
  1. package com.service;  
  2.   
  3. public class MyInterceptor2 {  
  4.     public void doAccessCheck(){  
  5.         System.out.println("before");  
  6.     }  
  7. }  

业务和接口

[java] view plaincopy
  1. package com.service;  
  2.   
  3. public interface PersonService {  
  4.     public void save(String name);  
  5.     public void update(String name);  
  6. }  

[java] view plaincopy
  1. package com.serviceImpl;  
  2.   
  3. import com.service.PersonService;  
  4.   
  5. public class PersonServiceImpl implements PersonService {  
  6.   
  7.     @Override  
  8.     public void save(String name) {  
  9.         // TODO Auto-generated method stub  
  10.         System.out.println("保存");  
  11.     }  
  12.   
  13.     @Override  
  14.     public void update(String name) {  
  15.         // TODO Auto-generated method stub  
  16.         System.out.println("修改");  
  17.     }  
  18.   
  19. }  

简单做个方法前通知,其他的都一样。

[java] view plaincopy
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
  4.     xsi:schemaLocation="http://www.springframework.org/schema/beans  
  5.            http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
  6.             http://www.springframework.org/schema/aop  
  7.            http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
  8.   
  9.     <aop:aspectj-autoproxy/>  
  10.       
  11.     <bean id="personServiceImpl" class="com.serviceImpl.PersonServiceImpl"></bean>  
  12.     <bean id="personInterceptor" class="com.service.MyInterceptor2"></bean>  
  13.       
  14.     <aop:config>  
  15.         <aop:aspect id="asp" ref="personInterceptor">  
  16.             <aop:pointcut id="myCut" expression="execution (* com.serviceImpl.PersonServiceImpl.*(..))"/>  
  17.             <aop:before pointcut-ref="myCut" method="doAccessCheck"/>  
  18.         </aop:aspect>       
  19.     </aop:config>  
  20. </beans>  

测试类

[java] view plaincopy
  1. package com.test;  
  2.   
  3.   
  4.   
  5. import org.junit.Test;  
  6. import org.springframework.context.ApplicationContext;  
  7. import org.springframework.context.support.ClassPathXmlApplicationContext;  
  8.   
  9. import com.service.PersonService;  
  10.   
  11. public class AopTest {  
  12.       
  13.     @Test  
  14.     public void interceptorTest(){  
  15.         ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");  
  16.         PersonService ps = (PersonService) ac.getBean("personServiceImpl");  
  17.         ps.save("aa");  
  18.     }  
  19. }  

posted on 2014-02-21 23:51  Java码界探秘  阅读(194)  评论(0编辑  收藏  举报

导航