Spring核心概念理解-IoC容器、DI、AOP

          每个java程序员对spring的基础概念都倒背入流,AOP(面向切面编程)、IOC(控制反转)、DI(依赖注入)。今天就这几个概念做一个简单深入的原理分析。AOP\IOC主要是思想和原则性的东西。DI只是IOC原则的实现。有点类似于java中,接口和接口实现类的关系。

一、AOP

  AOP(Aspect Oriented Programming) 可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术

        AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。

       主要功能:日志记录,性能统计,安全控制,事务处理,异常处理等等  
       主要意图:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码.

  二、IOC和DI

 在DI模式下,容器全权负责的组建的装配,容器以一些预先定义好的方式(例如setter方法或者构造函数)将匹配的资源注入到每个组件里。目前有三中类型的DI:

 setter注入:

setter注入,setter注入会存在一些问题,1. 容易出现忘记调用setter方法注入组件所需要的依赖,将会导致NullPointerException异常。2. 代码会存在安全问题,第一次注入后,不能阻止再次调用setter,除非添加额外的处理工作。但是由于setter注入非常简单所以非常流行(绝大多数Java IDE都支持自动生成setter方法)。
构造器注入,构造器注入能够一定程度上解决setter注入的问题。但是该中注入方式也会带来一些问题,如果组件有很多的依赖,则构造函数的参数列表将变得冗长,会降低代码可读性。
接口注入 ,该注入方式使用的非常少,它要求组件必须实现某个接口,容器正是通过这个接口实现注入依赖的。接口注入的缺点比较明显,使用接口注入需要实现特定的接口,而接口又特定于容器,所以组件对容器产生了依赖,一旦脱离容器,组件不能重用。这是一种"侵入式"注入。


其中"setter注入"和"构造器注入"是被广泛运用的,绝大多数的IoC容器都支持这两种DI类型。

        三、写一个示例:
             

    定义一个Connection 的接口:

package com.blog.blogsit.learn.spring;

import javax.activation.DataSource;
/**
 * @author hua.chen 2016年3月15日 下午11:16:05 <br>
 */
public interface Connection {
    public DataSource getDataSouce();
}
编写两个实现类:mysql 和Oracle的实现类

package com.blog.blogsit.learn.spring;

import javax.activation.DataSource;
/**
 * @author hua.chen 2016年3月15日 下午11:16:05 <br>
 */
public class MysqlConnection implements Connection {

    @Override
    public DataSource getDataSouce() {
        System.out.println("获取mysql数据源");
        return null;
    }

}
编写获取连接的服务类ConnectionService

package com.blog.blogsit.learn.spring;

import javax.activation.DataSource;
/**
 * @author hua.chen 2016年3月15日 下午11:16:05 <br>
 */
public class ConnectionService implements Connection {
    public Connection connection;

    public Connection getConnection() {
        return connection;
    }

    public void setConnection(Connection connection) {
        this.connection = connection;
    }

    @Override
    public DataSource getDataSouce() {
        return connection.getDataSouce();
    }

}
核心实现类IocContainer

package com.blog.blogsit.learn.spring;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.ObjectUtils;

import com.google.common.collect.Maps;

/**
 * @author hua.chen 2016年3月15日 下午11:16:05 <br>
 */
public class IocContainer {
    /** 内存存取 **/
    private Map<String, Object> component = Maps.newHashMap();

    public IocContainer() {
        Properties properties = new Properties();
        try {
            properties.load(new FileInputStream(
                    "/Users/blogsit/qunarProjects/blogsitjavabase/src/main/source/component.properties"));

            for (Map.Entry<Object, Object> entry : properties.entrySet()) {
                String key = ObjectUtils.toString(entry.getKey());
                String value = ObjectUtils.toString(entry.getValue());
                if (key.split("\\.").length == 1) {
                    this.handler(key, value);
                }
            }
            for (Map.Entry<Object, Object> entry : properties.entrySet()) {
                String key = ObjectUtils.toString(entry.getKey());
                String value = ObjectUtils.toString(entry.getValue());
                if (key.split("\\.").length == 2) {
                    this.handler(key, value);
                }
            }
        } catch (FileNotFoundException e) {
            System.err.println("配置文件不存在");
            e.printStackTrace();
        } catch (Exception e) {
            System.err.println("配置文件不存在");
            e.printStackTrace();
        }
    }

    /**
     * 核心类完成配置文件到对象的转化
     * 
     * @param key
     * @param value
     * @throws Exception
     */
    private void handler(String key, String value) throws Exception {
        String[] parts = key.split("\\.");
        if (parts.length == 1) {
            Object object = Class.forName(value).newInstance();
            this.component.put(key, object);
        } else if (parts.length == 2) {
            Object object = this.component.get(parts[0]);
            Object reference = this.component.get(value);
            // 通过setter注入
            PropertyUtils.setProperty(object, parts[1], reference);
        }
    }

    /**
     * 获取相对应的对象
     * 
     * @param key
     * @return
     */
    public Object getComponent(String key) {
        return this.component.get(key);
    }
}
编写测试类

package com.blog.blogsit.learn.spring;

/**
 * 测试类
 * 
 * @author hua.chen 2016年3月15日 下午11:38:44 <br>
 */
public class IocTestClient {
    public static void main(String[] args) {
        IocContainer container = new IocContainer();
        Connection connection = (Connection) container.getComponent("connectionService");
        connection.getDataSouce();
    }
}


我们看一下配置文件 component.properties
mysqlconnection=com.blog.blogsit.learn.spring.MysqlConnection
oracleconnection=com.blog.blogsit.learn.spring.OracleConnection
connectionService=com.blog.blogsit.learn.spring.ConnectionService
connectionService.connection=mysqlconnection
测试的输出结果:
获取mysql数据源
如果需要注入不同的类只需要修改component.properties文件。
connectionService.connection=oracleconnection



发布了100 篇原创文章 · 获赞 7 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/c123728529/article/details/50893520