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();
- }
2、创建一个Junit测试类
- package com.dao.impl;
- import com.dao.PersonDAO;
- public class PersonDaoImpl implements PersonDAO {
- @Override
- public void save() {
- System.out.println("保存");
- }
- }
方法instanceSpring1为Spring中的实现用到ClassPathXmlApplicationContext类,要实现IOC的原理要定义自己 的MyClassPathXmlApplicationContext首先读出beans.xml中的配置信息,通过反射机制实现bean,最后注入所需要的 bean。
- 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();
- }
- }
读取所的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);
- }
- }
注入属性实体
- 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();
- }
beans.xml配置
- 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();
- }
- }
- <?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");
- }
- }
如果你喜欢本文, 请长按二维码,关注公众号 分布式编程.
作者:分布式编程
出处:https://zthinker.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。