• Spring_Ioc容器


    一、Spring框架概念

      spring 是众多开源 java 项目中的一员,基于分层的 javaEE 应用一站式轻量级开源框架,主要核心是 Ioc(控制反转/依赖注入) 与 Aop(面向切面)两大技术,实现项目在开发过程中的轻松解耦, 提高项目的开发效率。

      在项目中引入spring的好处:

        ·降低组件之间的耦合度,实现软件各层之间的解耦

        ·可以使用容器提供的众多服务,如:事务管理服务、消息服务等

        ·当使用容器管理事务时,开发人员就不需要手工控制事务,也不需要处理复杂的事务传播

        ·容器提供单例模式支持,开发人员不再需要自己编写实现代码

        ·容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等功能

    二、Spring源码架构

      1、核心容器:spring-beans 和 spring-core 模块是 Spring 框架的核心模块,包含控制反转(Inversion of Control, IoC)依赖注入(Dependency Injection, DI) ,核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory, 工厂模式的实现。 BeanFactory 使用控制反转(IOC) 思想将应用程序的配置和依赖性规范与实际的应用程序代码分开。

      2、Spring 上下文 Spring Context: Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。 Spring 上下文包括企业服务,例如 JNDI、 EJB、电子邮件、国际化、校验和调度功能。

      3、Spring-Expression 模块是统一表达式语言(unified EL)的扩展模块,可以查询、管理运行中的对象,同时也方便的可以调用对象方法、操作数组、集合等。它的语法类似于传统 EL,但提供了额外的功能,最出色的要数函数调用和简单字符串的模板函数。

      4、Spring-AOP: spring-aop 是 Spring 的另一个核心模块, 在 Spring中,他是以 JVM 的动态代理技术为基础,然后设计出了一系列的Aop 横切实现,比如前置通知、返回通知、异常通知等。 通过其配置管理特性, Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。

      ......

     三、Spring容器工厂的简单实现

    package com.shsxt.factory;
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.XPath;
    import org.dom4j.io.SAXReader;
    
    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;
    
    public class Factory_01 implements Factory {
        // Map集合用来存放id和class
        Map<String, Object> map = new HashMap<>();
        List<Bean> beans = new ArrayList<>();
    
        // 实例化工厂对象时就完成以下操作
        public Factory_01(String fileName) {
            // xml解析
            this.pathXml(fileName);
            // 实例化对象
            this.instanceBean();
            // 属性赋值
            this.setProperty();
        }
    
        // 属性赋值
        private void setProperty() {
            try {
                if(null!=beans && beans.size()>0){
                    for(Bean bean:beans){
                        List<Property> properties=bean.getProperties();
                        if(null!=properties && properties.size()>0){
                            for(Property property:properties){
                                // 得到property的id和ref
                                String id=property.getId();
                                String ref=property.getRef();
                                // set方法中首字母大写
                                id=id.toUpperCase().charAt(0)+id.substring(1);
                                // 获取到当前class
                                Class clz=map.get(bean.getId()).getClass();
                                // 找到set方法
                                Method method=clz.getDeclaredMethod("set"+id,map.get(ref).getClass());
                                method.invoke(map.get(bean.getId()),map.get(ref));
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // 实例化
        private void instanceBean() {
            if (null != beans && beans.size() > 0) {
                try {
                    for (Bean bean : beans) {
                        // 放到map集合中,通过key找到value,实例化该对象
                        map.put(bean.getId(), Class.forName(bean.getClz()).newInstance());
                    }
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                }
    
            }
        }
    
        /**
         * xml解析
         *
         * @param fileName xml文件名
         */
        private void pathXml(String fileName) {
            // 获取xml文件
            URL url = this.getClass().getClassLoader().getResource(fileName);
            try {
                if (null != url) {
                    // 获取解析器
                    SAXReader saxReader = new SAXReader();
                    // 解析xml文件,返回document对象
                    Document document = saxReader.read(url);
                    // 获取xpath对象
                    XPath xPath = document.createXPath("beans/bean");
                    // 查询选择的节点,返回的是list集合
                    List<Element> elements = xPath.selectNodes(document);
                    // 为空判断
                    if (null != elements && elements.size() > 0) {
                        for (Element element : elements) {
                            // 获取property
                            xPath = document.createXPath("property");
                            // 查询选择的节点
                            List<Element> subElements = xPath.selectNodes(element);
                            // 为空判断
                            List<Property> properties = null;
                            // 实例化Bean
                            Bean bean = new Bean(element.attributeValue("id"), element.attributeValue("class"));
                            if (null != subElements && subElements.size() > 0) {
                                properties = new ArrayList<>();
                                for (Element subElement : subElements) {
                                    // 实例化Property
                                    Property property = new Property(subElement.attributeValue("id"), subElement.attributeValue("ref"));
                                    // 将对象放到集合中
                                    properties.add(property);
                                }
                                bean.setProperties(properties);
                            }
                            beans.add(bean);
                        }
                    }
                }
            } catch (DocumentException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public Object getObj(String name) {
            // 通过id返回class
            return map.get(name);
        }
    }
    View Code

    四、Spring多文件的加载情况

      1、ClassPathXmlApplicationContext类的构造器参数是一个可变长参数

          可同时配置多个xml文件

      2、import标签,将自配置文件导入总配置

        

    四、Spring Ioc实例化bean的三种方式

      1、构造器的方式实例化bean对象

        通过默认构造器实例化bean对象,默认空构造器必须存在

      2、静态工厂方式实例化bean

        要有工厂类和静态工厂方法

          通过反射调用静态工厂的静态方法,将该静态方法的返回值作为bean的实例,可以统一管理各个bean的创建

       3、实例化工厂方式实例化bean

        工厂类和实例化方法

          工厂方法为非静态,需要配置工厂bean,并在bean中配置factory-bean和factory-method属性

          1) 可用于集成其他框架的bean创建管理方法  2)能够使bean和factory的角色互换

    五、Spring 依赖注入

      在面向接口编程中,依赖接口可以动态传入多种实现

      1、set注入

        property标签,属性的set方法(不会出现循环引用问题)

        

        name:属性名称;ref:bean对象的引用;value:给属性直接赋值(List,Set,Map,properties)

        

      2、构造器注入

        constructor-arg标签,带参构造器(会出现循环引用问题,彼此互相依赖对方导致bean无法实例化)

        

        name:属性名称;ref:bean对象id的引用;index:属性的索引

      3、静态工厂注入

        

      4、实例化工厂注入

        

    六、注解方式注入bean

      xml配置:加入context命名空间和xsd地址

      添加<context:annotation-config/>配置

      @Resource (属于J2EE)

      @Autowired (Spring)

      常用于属性字段或set方法上

      区别:

         @Autowired 默认按bean的类型匹配,和@Qualifier配合使用可以修改按名称匹配

         @Resource 默认按名称进行装配,可以通过name属性指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行匹配注入,如果注解写在set方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配(当name属性指定,只会按照名称装配)

    注解方式注入的简单模拟:

      

    package com.shsxt02;
    
    import com.shsxt.annotaioms.Component;
    import com.shsxt.annotaioms.Component02;
    import com.shsxt02.controller.UserController;
    
    import java.io.File;
    import java.lang.reflect.Field;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    public class Test {
    
        private static List<String>  clz=new ArrayList<>();
        private static  Map<String,Object> map=new HashMap<>();
    
        public static void main(String[] args){
            String pkg="com.shsxt02";
            // 获取标记注解的类
            getClZ(pkg);
            // 实例化这些类
            instanceClz();
            // 属性赋值
            property();
            UserController userController= (UserController) map.get("userController");
            userController.test();
        }
    
        private static void property() {
            try {
                if (null!=map){
                    for(Map.Entry entry:map.entrySet()){
                        Field[] fields=entry.getValue().getClass().getDeclaredFields();
                        if (null!=fields){
                            for(Field field:fields){
                                Component02 component02=field.getAnnotation(Component02.class);
                                if (null!=component02){
                                    field.setAccessible(true);
                                    field.set(entry.getValue(),map.get(component02.value()));
                                }
                            }
                        }
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    
    
        private static void instanceClz() {
            try {
                if (null!=clz && clz.size()>0){
                    for(String cls:clz){
                        //System.out.println(str);
                        cls=cls.replace(".class","");
                        //System.out.println(cls);
                        Component component=Class.forName(cls).getAnnotation(Component.class);
                        if (null!=component){
                            //System.out.println(cls);
                            String id= getId(cls);
                            Object obj=Class.forName(cls).newInstance();
                            map.put(id,obj);
                        }
                    }
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    
        private static String getId(String cls) {
            cls=cls.substring(cls.lastIndexOf(".")+1);
            cls= cls.toLowerCase().charAt(0)+cls.substring(1);
            return cls;
        }
    
        private static void getClZ(String pkg) {
            // 获取url
            URL url=Thread.currentThread().getContextClassLoader().getResource(repStr(pkg));
            String urlPath=url.getFile();
            //System.out.println(urlPath);
            String[] subFileStrs=new File(urlPath).list();
            for(String str:subFileStrs){
                String subFilePath=urlPath+"/"+str;
                //System.out.println(subFilePath);
                File subFile=new File(subFilePath);
                if (subFile.isDirectory()){
                    //System.out.println(pkg+"."+subFile.getName());
                    getClZ(pkg+"."+subFile.getName());
                }else{
                    clz.add(pkg+"."+subFile.getName());
                }
            }
        }
    
        private static String repStr(String str){
            str=str.replace(".","/");
            return str;
        }
    }
    View Code

    七、Spring IOC 容器自动扫描管理bean

      xml配置<context:component-scan base-package=""/>

      建议的注解

        Dao层:@Repository

        Service层:@Service

        控制层:@Controller

        不明确:@Component

    八、Bean的作用域问题(scope)

      1、singleton作用域(单例,默认)

        lazy-init 懒加载 默认为false

          如果等于true时,spring容器启动的时候不会去实例化这个bean,而是在程序调用时才会去实例化

          在启动情况下实例化所有singleton的bean对象并缓存与容器中单例的好处:

            1、提前发现潜在的配置问题

            2、bean对象存在于缓存中,使用时不用再实例化bean,提高执行性能

        

          无状态对象适合做单例bean对象(无可变的成员变量)

      2、prototype作用域(原型)

        每次向Spring容器请求获取Bean都返回一个全新的Bean,相对于“singleton”来说就是不缓存Bean。IOC不会维护该对象

      3、Web应用中的作用域(request、session、globalsession)

        request作用域:每一次请求

        session:当前会话

        globlasession:同session(Portlet环境)

  • 相关阅读:
    html页面模板布局内容的继承,block
    url分发
    显示年月,注册页面和后台数据交互,不涉及数据库
    static文件夹中文件引用方式,如html页面引用js
    pycharm写django之返回一个页面
    pycharm编写django第一步
    VUE清除keepalive页面缓存
    js设置html根节点的style字体【Vue动态调整全局字体大小】
    npm 依赖重新安装或更新版本
    antd 自定义表头slots.title不生效
  • 原文地址:https://www.cnblogs.com/dhome/p/9704193.html
Copyright © 2020-2023  润新知