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

Spring IOC、DI、AOP原理和实现

2014-02-28 10:07 281 查看

(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接口和接口的实现类
[java] view plaincopyprint?package com.dao;  
  
public interface PersonDAO {  
    public void save();  
}  
package com.dao;

public interface PersonDAO {
public void save();
}


[java]
view plaincopyprint?

package com.dao.impl;  
  
import com.dao.PersonDAO;  
  
public class PersonDaoImpl implements PersonDAO {  
  
    @Override  
    public void save() {  
        System.out.println("保存");  
    }  
  
}  

package com.dao.impl;

import com.dao.PersonDAO;

public class PersonDaoImpl implements PersonDAO {

@Override
public void save() {
System.out.println("保存");
}

}

2、创建一个Junit测试类

[java]
view plaincopyprint?

package com.test;  
  
import org.junit.Test;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
  
import com.dao.PersonDAO;  
import com.myUtil.MyClassPathXmlApplicationContext;  
import com.service.PersonService;  
  
  
public class PersonTest {  
      
    @Test  
    public void instanceSpring1(){  
        /** 
         *  
         * spring 的实现 
         */  
        //IOC  
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");  
        PersonDAO pd = (PersonDAO) ac.getBean("personDAO");  
        pd.save();  
        //DI  
        PersonService ps = (PersonService) ac.getBean("personService");  
        ps.save();  
    }  
      
    @Test  
    public void instanceSpring2(){  
          
        /** 
         * 我的实现 
         *  
         */  
        MyClassPathXmlApplicationContext mac = new MyClassPathXmlApplicationContext("beans.xml");  
        PersonDAO mpd = (PersonDAO) mac.getBean("personDAO");  
        mpd.save();  
        //DI  
        PersonService ps = (PersonService) mac.getBean("personService");  
        ps.save();  
    }  
      
}  

package com.test;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.dao.PersonDAO;
import com.myUtil.MyClassPathXmlApplicationContext;
import com.service.PersonService;

public class PersonTest {

@Test
public void instanceSpring1(){
/**
*
* spring 的实现
*/
//IOC
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
PersonDAO pd = (PersonDAO) ac.getBean("personDAO");
pd.save();
//DI
PersonService ps = (PersonService) ac.getBean("personService");
ps.save();
}

@Test
public void instanceSpring2(){

/**
* 我的实现
*
*/
MyClassPathXmlApplicationContext mac = new MyClassPathXmlApplicationContext("beans.xml");
PersonDAO mpd = (PersonDAO) mac.getBean("personDAO");
mpd.save();
//DI
PersonService ps = (PersonService) mac.getBean("personService");
ps.save();
}

}
方法instanceSpring1为Spring中的实现用到ClassPathXmlApplicationContext类,要实现IOC的原理要定义自己

的MyClassPathXmlApplicationContext首先读出beans.xml中的配置信息,通过反射机制实现bean,最后注入所需要的
bean。

[java]
view plaincopyprint?

package com.myUtil;  
import java.beans.Introspector;  
import java.beans.PropertyDescriptor;  
import java.lang.reflect.Method;  
import java.net.URL;  
import java.util.ArrayList;  
import java.util.HashMap;  
import java.util.List;  
import java.util.Map;  
import org.dom4j.Document;  
import org.dom4j.Element;  
import org.dom4j.io.SAXReader;  
  
public class MyClassPathXmlApplicationContext {  
    // xml所有的属性  
    private ArrayList<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();  
    // xml中所有的bean  
    private Map<String, Object> sigletons = new HashMap<String, Object>();  
  
    public MyClassPathXmlApplicationContext(String file) {  
        readXml(file);  
        instanceBeans();  
        instanceObject();  
    }  
  
    /** 
     * 注入 
     */  
    private void instanceObject() {  
        for (BeanDefinition beanDefinition : beanDefinitions) {  
            //判断有没有注入属性  
            if (beanDefinition.getProperty() != null) {  
                Object bean = sigletons.get(beanDefinition.getId());  
                if (bean != null) {  
                    try {  
                        //得到被注入bean的所有的属性  
                        PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();  
                        //得到所有的注入bean属性  
                        for(PropertyDefinition propertyDefinition:beanDefinition.getProperty()){  
                            for(PropertyDescriptor propertyDescriptor:ps){  
                                if(propertyDescriptor.getName().equals(propertyDefinition.getName())){  
                                    Method setter = propertyDescriptor.getWriteMethod();//获取set方法  
                                    if(setter!=null){  
                                        setter.setAccessible(true);//得到private权限  
                                        //注入属性  
                                        setter.invoke(bean, sigletons.get(propertyDefinition.getRef()));  
                                    }  
                                    break;  
                                }  
                            }  
                        }  
                    } catch (Exception e) {  
                        // TODO Auto-generated catch block  
                        e.printStackTrace();  
                    }  
                }  
            }  
        }  
    }  
  
    /** 
     * 实例所有的bean 
     */  
    private void instanceBeans() {  
        for (int i = 0; i < beanDefinitions.size(); i++) {  
            BeanDefinition bd = beanDefinitions.get(i);  
            try {  
                try {  
                    if (bd.getClassName() != null  
                            && !bd.getClassName().equals(""))  
                        sigletons.put(bd.getId(), Class.forName(  
                                bd.getClassName()).newInstance());  
                } catch (InstantiationException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                } catch (IllegalAccessException e) {  
                    // TODO Auto-generated catch block  
                    e.printStackTrace();  
                }  
            } catch (ClassNotFoundException e) {  
                // TODO Auto-generated catch block  
                e.printStackTrace();  
            }  
        }  
    }  
  
    /** 
     * 读xml 
     *  
     * @param file 
     */  
    private void readXml(String file) {  
        try {  
            SAXReader reader = new SAXReader(); // 使用SAX方式解析XML  
            URL xmlPath = this.getClass().getClassLoader().getResource(file);  
            Document doc = reader.read(xmlPath);  
            Element root = doc.getRootElement(); // 取得根节点  
            List<Element> beans = root.elements();  
            for (Element element : beans) {  
                String id = element.attributeValue("id");// id;  
                String clazz = element.attributeValue("class");  
                BeanDefinition bd = new BeanDefinition(id, clazz);  
                // 读取子元素  
                if (element.hasContent()) {  
                    List<Element> propertys = element.elements();  
                    for (Element property : propertys) {  
                        String name = property.attributeValue("name");  
                        String ref = property.attributeValue("ref");  
                        PropertyDefinition pd = new PropertyDefinition(name,  
                                ref);  
                        bd.getProperty().add(pd);  
                    }  
                }  
                beanDefinitions.add(bd);  
            }  
        } catch (Exception e) {  
            // TODO: handle exception  
        }  
    }  
  
    /** 
     * 通过名字得到bean 
     *  
     * @param str 
     * @return 
     */  
    public Object getBean(String str) {  
        return sigletons.get(str);  
    }  
  
}  

package com.myUtil;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class MyClassPathXmlApplicationContext {
// xml所有的属性
private ArrayList<BeanDefinition> beanDefinitions = new ArrayList<BeanDefinition>();
// xml中所有的bean
private Map<String, Object> sigletons = new HashMap<String, Object>();

public MyClassPathXmlApplicationContext(String file) {
readXml(file);
instanceBeans();
instanceObject();
}

/**
* 注入
*/
private void instanceObject() {
for (BeanDefinition beanDefinition : beanDefinitions) {
//判断有没有注入属性
if (beanDefinition.getProperty() != null) {
Object bean = sigletons.get(beanDefinition.getId());
if (bean != null) {
try {
//得到被注入bean的所有的属性
PropertyDescriptor[] ps = Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
//得到所有的注入bean属性
for(PropertyDefinition propertyDefinition:beanDefinition.getProperty()){
for(PropertyDescriptor propertyDescriptor:ps){
if(propertyDescriptor.getName().equals(propertyDefinition.getName())){
Method setter = propertyDescriptor.getWriteMethod();//获取set方法
if(setter!=null){
setter.setAccessible(true);//得到private权限
//注入属性
setter.invoke(bean, sigletons.get(propertyDefinition.getRef()));
}
break;
}
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}

/**
* 实例所有的bean
*/
private void instanceBeans() {
for (int i = 0; i < beanDefinitions.size(); i++) {
BeanDefinition bd = beanDefinitions.get(i);
try {
try {
if (bd.getClassName() != null
&& !bd.getClassName().equals(""))
sigletons.put(bd.getId(), Class.forName(
bd.getClassName()).newInstance());
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

/**
* 读xml
*
* @param file
*/
private void readXml(String file) {
try {
SAXReader reader = new SAXReader(); // 使用SAX方式解析XML
URL xmlPath = this.getClass().getClassLoader().getResource(file);
Document doc = reader.read(xmlPath);
Element root = doc.getRootElement(); // 取得根节点
List<Element> beans = root.elements();
for (Element element : beans) {
String id = element.attributeValue("id");// id;
String clazz = element.attributeValue("class");
BeanDefinition bd = new BeanDefinition(id, clazz);
// 读取子元素
if (element.hasContent()) {
List<Element> propertys = element.elements();
for (Element property : propertys) {
String name = property.attributeValue("name");
String ref = property.attributeValue("ref");
PropertyDefinition pd = new PropertyDefinition(name,
ref);
bd.getProperty().add(pd);
}
}
beanDefinitions.add(bd);
}
} catch (Exception e) {
// TODO: handle exception
}
}

/**
* 通过名字得到bean
*
* @param str
* @return
*/
public Object getBean(String str) {
return sigletons.get(str);
}

}
读取所的bean实体

[java]
view plaincopyprint?

package com.myUtil;  
  
import java.util.ArrayList;  
import java.util.List;  
  
public class BeanDefinition {  
    private String id;  
    private String className;  
    private List<PropertyDefinition> property = new ArrayList<PropertyDefinition>();  
  
    public BeanDefinition(String id, String className) {  
        super();  
        this.id = id;  
        this.className = className;  
    }  
  
    public String getId() {  
        return id;  
    }  
  
    public void setId(String id) {  
        this.id = id;  
    }  
  
    public String getClassName() {  
        return className;  
    }  
  
    public void setClassName(String className) {  
        this.className = className;  
    }  
  
    public List<PropertyDefinition> getProperty() {  
        return property;  
    }  
  
    public void setProperty(List<PropertyDefinition> property) {  
        this.property = property;  
    }  
  
}  

package com.myUtil;

import java.util.ArrayList;
import java.util.List;

public class BeanDefinition {
private String id;
private String className;
private List<PropertyDefinition> property = new ArrayList<PropertyDefinition>();

public BeanDefinition(String id, String className) {
super();
this.id = id;
this.className = className;
}

public String getId() {
return id;
}

public void setId(String id) {
this.id = id;
}

public String getClassName() {
return className;
}

public void setClassName(String className) {
this.className = className;
}

public List<PropertyDefinition> getProperty() {
return property;
}

public void setProperty(List<PropertyDefinition> property) {
this.property = property;
}

}


注入属性实体

[java]
view plaincopyprint?

package com.myUtil;  
  
public class PropertyDefinition {  
    private String name;  
    private String ref;  
  
    public PropertyDefinition(String name, String ref) {  
        this.name = name;  
        this.ref = ref;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public String getRef() {  
        return ref;  
    }  
  
    public void setRef(String ref) {  
        this.ref = ref;  
    }  
  
}  

package com.myUtil;

public class PropertyDefinition {
private String name;
private String ref;

public PropertyDefinition(String name, String ref) {
this.name = name;
this.ref = ref;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getRef() {
return ref;
}

public void setRef(String ref) {
this.ref = ref;
}

}


业务接口和实现类

[java]
view plaincopyprint?

package com.service;  
  
public interface PersonService {  
    public void save();  
}  

package com.service;

public interface PersonService {
public void save();
}


[java]
view plaincopyprint?

package com.service.impl;  
  
import com.dao.PersonDAO;  
import com.service.PersonService;  
  
public class PersonServiceImpl implements PersonService{  
    private PersonDAO pdo;  
  
    public PersonDAO getPdo() {  
        return pdo;  
    }  
  
    public void setPdo(PersonDAO pdo) {  
        this.pdo = pdo;  
    }  
  
    @Override  
    public void save() {  
        pdo.save();  
    }  
      
}  

package com.service.impl;

import com.dao.PersonDAO;
import com.service.PersonService;

public class PersonServiceImpl implements PersonService{
private PersonDAO pdo;

public PersonDAO getPdo() {
return pdo;
}

public void setPdo(PersonDAO pdo) {
this.pdo = pdo;
}

@Override
public void save() {
pdo.save();
}

}
beans.xml配置

[java]
view plaincopyprint?

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">  
            
    <bean id="personDAO" class="com.dao.impl.PersonDaoImpl"></bean>  
    <bean id="personService" class="com.service.impl.PersonServiceImpl">  
        <property name="pdo" ref="personDAO"></property>  
    </bean>  
</beans>  

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> 
<bean id="personDAO" class="com.dao.impl.PersonDaoImpl"></bean>
<bean id="personService" class="com.service.impl.PersonServiceImpl">
<property name="pdo" ref="personDAO"></property>
</bean>
</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 plaincopyprint?

package com.service;  
  
import org.aspectj.lang.annotation.Aspect;  
import org.aspectj.lang.annotation.Before;  
import org.aspectj.lang.annotation.Pointcut;  
  
@Aspect  
public class MyInterceptor {  
    @Pointcut("execution (* com.serviceImpl.PersonServiceImpl.*(..))")  
    private void myMethod(){};  
      
    @Before("myMethod()")  
    public void doAccessCheck(){  
        System.out.println("before");  
    }  
      
}  

package com.service;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MyInterceptor {
@Pointcut("execution (* com.serviceImpl.PersonServiceImpl.*(..))")
private void myMethod(){};

@Before("myMethod()")
public void doAccessCheck(){
System.out.println("before");
}

}


[java]
view plaincopyprint?

package com.service;  
  
public class MyInterceptor2 {  
    public void doAccessCheck(){  
        System.out.println("before");  
    }  
}  

package com.service;

public class MyInterceptor2 {
public void doAccessCheck(){
System.out.println("before");
}
}


业务和接口

[java]
view plaincopyprint?

package com.service;  
  
public interface PersonService {  
    public void save(String name);  
    public void update(String name);  
}  

package com.service;

public interface PersonService {
public void save(String name);
public void update(String name);
}


[java]
view plaincopyprint?

package com.serviceImpl;  
  
import com.service.PersonService;  
  
public class PersonServiceImpl implements PersonService {  
  
    @Override  
    public void save(String name) {  
        // TODO Auto-generated method stub  
        System.out.println("保存");  
    }  
  
    @Override  
    public void update(String name) {  
        // TODO Auto-generated method stub  
        System.out.println("修改");  
    }  
  
}  

package com.serviceImpl;

import com.service.PersonService;

public class PersonServiceImpl implements PersonService {

@Override
public void save(String name) {
// TODO Auto-generated method stub
System.out.println("保存");
}

@Override
public void update(String name) {
// TODO Auto-generated method stub
System.out.println("修改");
}

}


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

[java]
view plaincopyprint?

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans  
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
            http://www.springframework.org/schema/aop  
           http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">  
  
    <aop:aspectj-autoproxy/>  
      
    <bean id="personServiceImpl" class="com.serviceImpl.PersonServiceImpl"></bean>  
    <bean id="personInterceptor" class="com.service.MyInterceptor2"></bean>  
      
    <aop:config>  
        <aop:aspect id="asp" ref="personInterceptor">  
            <aop:pointcut id="myCut" expression="execution (* com.serviceImpl.PersonServiceImpl.*(..))"/>  
            <aop:before pointcut-ref="myCut" method="doAccessCheck"/>  
        </aop:aspect>       
    </aop:config>  
</beans>  

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> 
<aop:aspectj-autoproxy/>

<bean id="personServiceImpl" class="com.serviceImpl.PersonServiceImpl"></bean>
<bean id="personInterceptor" class="com.service.MyInterceptor2"></bean>

<aop:config>
<aop:aspect id="asp" ref="personInterceptor">
<aop:pointcut id="myCut" expression="execution (* com.serviceImpl.PersonServiceImpl.*(..))"/>
<aop:before pointcut-ref="myCut" method="doAccessCheck"/>
</aop:aspect>
</aop:config>
</beans>


测试类

[java]
view plaincopyprint?

package com.test;  
  
  
  
import org.junit.Test;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
  
import com.service.PersonService;  
  
public class AopTest {  
      
    @Test  
    public void interceptorTest(){  
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");  
        PersonService ps = (PersonService) ac.getBean("personServiceImpl");  
        ps.save("aa");  
    }  
}  



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring