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接口和接口的实现类
package com.dao;

public interface PersonDAO {
	public void save();
}
package com.dao.impl;

import com.dao.PersonDAO;

public class PersonDaoImpl implements PersonDAO {

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

}

2、创建一个Junit测试类

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
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实体
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;

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.service;

public interface PersonService {
	public void 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配置
<?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定义的切面类

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;

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

业务和接口

package com.service;

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

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("修改");
	}

}

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

<?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>

测试类

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");
	}
}



  • 6
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值