Spring框架(Ioc+DI)

Spring框架(Ioc+DI)

一、MVC思想

  • M:Model 数据模型(User.java)

  • V:view 视图(页面jsp,html...)

  • C:Controller控制器(控制业务逻辑)

框架介绍:

| bean管理 | Spring框架 |

| ---- | --- |

|持久层操作|MyBatis Hibernate Spring Data Jpa|

|servlet开发 | SpringMVC框架 Struts2|

|微服务|Dubbo (阿里) Spring Boot和Spring Cloud|

|缓存| Redis ...|

二、Spring框架概念

spring 是众多开源java项目中的一员,基于分层的 javaEE 应用一站式轻量级开源框架,主要核心是 Ioc(控制反转/依赖注入)与Aop(面向切面)两大技术,实现项目在开发过程中的轻松解耦,提高项目的开发效率。 在项目中引入spring,立即可以带来下面的好处:降低组件之间的耦合度,实现软件各层之间的解耦。可以使用容器提供的众多服务,如:事务管理服务、消息服务等等。当我们使用容器管理事务时,开发人员就不再需要手工控制事务.也不需处理复杂的事务传播。 容器提供单例模式支持,开发人员不再需要自己 编写实现代码。 容器提供了 AOP 技术,利用它很容易实现如权限拦截、运行 期监控等功能。

核心点:Ioc+DI+Aop

SSM:Spring + SpringMVC + MyBatis

三、Spring框架环境搭建

  1. 创建maven项目

  2. 添加 spring 框架依赖


<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>4.3.9.RELEASE</version>

</dependency>

  1. 编写 bean和测试代码

package com.shsxt.service; 

public class HelloService { 

public void hello(){ System.out.println("hello spring"); 

    } 

}

  1. Spring配置文件的编写

在 src 下新建xml文件,并拷贝官网文档提供的模板内容到 xml 中,配置 bean 到xml中,把对应bean 纳入到 spring 容器来管理


<?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.xsd">

    <!--

       xmlns 即 xml namespace  xml使用的命名空间

       xmlns:xsi 即xml schema instance xml 遵守的具体规范

       xsi:schemaLocation 本文档xml遵守的规范 官方指定

     -->

    <bean id="helloService" class="com.shsxt.dao.HelloService"></bean>

</beans>

  1. 验证Spring框架是否搭建成功

测试文件:

       /***

         * 1. 加载配置文件

         * 2. 获取HelloService的Bean对象

         * 3.使用bean

         * */

        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

        HelloService helloService = (HelloService) context.getBean("helloService");

        helloService.hello();

四、简单模拟Ioc容器

  1. 引入xml解析dom4j依赖

    <dependency>

      <groupId>dom4j</groupId>

      <artifactId>dom4j</artifactId>

      <version>1.6.1</version>

    </dependency>

    <dependency>

      <groupId>jaxen</groupId>

      <artifactId>jaxen</artifactId>

      <version>1.1.6</version>

    </dependency>

2.工厂接口定义


package com.shsxt;

/**

 * Created by xlf on 2019/7/4.

 */

public interface ApplicationContext {

    public Object getBean(String id);

}

  1. bean属性对象定义

package com.shsxt;

/**

 * Created by xlf on 2019/7/4.

 */

public class SxtBean {

    private String id;

    private String clazz;

    public SxtBean() {

    }

    public SxtBean(String id, String clazz) {

        this.id = id;

        this.clazz = clazz;

    }

    public String getId() {

        return id;

    }

    public void setId(String id) {

        this.id = id;

    }

    public String getClazz() {

        return clazz;

    }

    public void setClazz(String clazz) {

        this.clazz = clazz;

    }

}

  1. 实现类

package com.shsxt;

import org.dom4j.Document;

import org.dom4j.DocumentException;

import org.dom4j.Element;

import org.dom4j.io.SAXReader;

import java.net.MalformedURLException;

import java.net.URL;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

/**

 * Created by xlf on 2019/7/4.

 */

public class SxtApplicationContext implements ApplicationContext {

    /***

     * 1. 读取xml并解析

     * 2. 反射生成bean对象

     * 3. 返回执行bean

     * */

    private String xmlPath;// xml配置文件路径

    private List<SxtBean> sxtBeanList = new ArrayList<>();// 存储解析结果

    private Map<String, Object> beanMap = new HashMap<>();// 存储反射结果

    public SxtApplicationContext(String xmlPath) throws ClassNotFoundException, InstantiationException, IllegalAccessException {

        this.xmlPath = xmlPath;

        // 解析xml

        parseXml(xmlPath);

        // 反射生成bean

        initBean();

    }

    /**

     * 初始化Bean

     */

    private void initBean() throws ClassNotFoundException, IllegalAccessException, InstantiationException {

        if(sxtBeanList.size()>0){

            for(SxtBean bean : sxtBeanList){

                String id = bean.getId();

                String clazz = bean.getClazz();

                beanMap.put(id, Class.forName(clazz).newInstance());

            }

        }

    }

    /**

     * 解析xml

     * @param xmlPath

     */

    private void parseXml(String xmlPath) {

        if(null!=xmlPath && !"".equals(xmlPath)){

            // dom4j

            SAXReader reader = new SAXReader();

            try {

                // 1. 拿到xml

                URL url = this.getClass().getClassLoader().getResource(xmlPath);

                Document document = reader.read(url);

                // 2. 解析xml

                List<Element> list = document.selectNodes("/beans/bean");

                // 3. 获取属性值

                for (Element e : list){

//                    System.out.println("id: "+e.attributeValue("id")+" class: "+e.attributeValue("class"));

                    String id = e.attributeValue("id");

                    String clazz = e.attributeValue("class");

                    sxtBeanList.add(new SxtBean(id, clazz));

                }

            } catch (DocumentException e) {

                e.printStackTrace();

            }

        }else{

            System.err.println("文件不存在");

        }

    }

    @Override

    public Object getBean(String id) {

        return beanMap.get(id);

    }

}

五、多文件加载情况

  1. 编写多个配置文件

如:Dao.xml,Service.xml,Controller.xml

  1. 测试有两种方式

方式一:


        ApplicationContext context = new ClassPathXmlApplicationContext("Dao.xml","Service.xml","Controller.xml");

        UserDao userDao = (UserDao) context.getBean("userDao");

        userDao.show();

        UserService userService = (UserService) context.getBean("userService");

        userService.show();

        UserController userController = (UserController) context.getBean("userController");

        userController.show();

方式二:


将多个xml文件导入spring.xml中:

    <import resource="dao.xml"/>

    <import resource="service.xml"/>

    <import resource="controller.xml"/>

测试:

        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

        UserDao userDao = (UserDao) context.getBean("userDao");

        userDao.show();

        ......



六、Spring Ioc实例化bean对象的三种方式

1、构造器

类中必须有空构造


<!-- 1. 通过构造器 -->

    <bean id="helloService" class="com.shsxt.service.HelloService"></bean>

2、静态工厂方法

可以控制bean的初始化,但是要保证工厂方法必须是静态方法


配置

    <!-- 2. 静态工厂, 初始化bean -->

    <bean id="personService" class="com.shsxt.factory.StaticFactory" factory-method="getPersonService"></bean>


静态工厂类

package com.shsxt.factory;

import com.shsxt.service.PersonService;

/**

 * Created by xlf on 2019/7/4.

 */

public class StaticFactory {

    public static PersonService getPersonService(){

        return new PersonService("sxt");

    }

}

3、实例化工厂

不局限于静态方法。多用于框架整合。


配置

   <!-- 3. 实例化工厂 -->

    <bean id="initFactory" class="com.shsxt.factory.InitFactory"></bean>

    <bean id="accountService" factory-bean="initFactory" factory-method="getAccountService"></bean>


工厂类

package com.shsxt.factory;

import com.shsxt.service.AccountService;

import com.shsxt.service.PersonService;

/**

 * Created by xlf on 2019/7/4.

 */

public class InitFactory {

    public AccountService getAccountService(){

        return new AccountService();

    }

}

三种方式的比较

方式一:通过 bean 的缺省构造函数创建,当各个 bean 的业务逻辑相互比较独立的时 候或者和外界关联较少的时候可以使用。

方式二:利用静态 factory 方法创建,可以统一管理各个 bean 的创建,如各个 bean 在 创建之前需要相同的初始化处理,则可用这个 factory 方法进行统一的处理等等。

方式三:利用实例化 factory 方法创建,即将 factory 方法也作为了业务 bean 来控制, 1 可用于集成其他框架的 bean 创建管理方法,2 能够使 bean 和 factory 的角色互换。

开发中项目一般使用一种方式实例化 bean,项目开发基本采用第一种方式,交 给 spring 托管,使用时直接拿来使用即可。

七、依赖注入

依赖注入:控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

注入方式

1、set注入(最常用的方式)

spring.xml配置


    <!-- 1. set注入; 条件必须存在setter方法 -->

    <bean id="userService" class="com.shsxt.service.UserService">

    <property name="userDao" ref="userDao"></property>

    </bean>

java类


package com.shsxt.service;

import com.shsxt.dao.UserDao;

/**

 * Created by xlf on 2019/7/4.

 */

public class UserService {

    // spring的依赖注入

    private UserDao userDao;

    public void test(){

        userDao.addUser();

    }

    // 必须存在

    public void setUserDao(UserDao userDao) {

        System.out.println("setUserDao...");

        this.userDao = userDao;

    }

}

基本数据类型set注入


<bean id="userServiceImpl" class="com.shsxt.service.impl.UserServiceImpl"> 

<property name="userDao" ref="userDao"></property> 

<property name="userName" value="sxt"> </property> 

<property name="price" value="123"> </property> 

</bean> 同时对应 Service 提供对应属性字段 以及 get 、set 方法即可

2、构造器注入

xml配置


   <!-- 2. 构造注入 -->

    <bean id="accountService" class="com.shsxt.service.AccountService">

    <constructor-arg name="userDao" ref="userDao"></constructor-arg>

    </bean>

java类


package com.shsxt.service;

import com.shsxt.dao.UserDao;

/**

 * Created by xlf on 2019/7/4.

 */

public class AccountService {

    // spring的依赖注入

    private UserDao userDao;

    public AccountService(UserDao userDao) {

        this.userDao = userDao;

    }

    public void test(){

        userDao.addUser();

    }

}

3、静态工厂注入

xml配置


    <!-- 3. 静态工厂注入 -->

    <bean id="userDao" class="com.shsxt.factory.StaticFactory" factory-method="createUserDao"></bean>

    <bean id="userService" class="com.shsxt.service.UserService">

    <property name="userDao" ref="userDao"></property>

    </bean>

静态工厂类同上

4、实例化工厂注入

xml配置


    <!-- 4. 实例工厂注入 -->

    <bean id="instanceFactory" class="com.shsxt.factory.InstanceFactory"></bean>

    <bean id="userDao" factory-bean="instanceFactory" factory-method="createUserDao"></bean>

    <bean id="userService" class="com.shsxt.service.UserService">

    <property name="userDao" ref="userDao"></property>

    </bean>

工厂类同上

5、p标签和c标签


    <!-- p标签 -->

    <bean id="userService" class="com.shsxt.service.UserService"

          p:userDao-ref="userDao">

    </bean>

        <!-- c标签 -->

    <bean id="accountService" class="com.shsxt.service.AccountService"

          c:_0-ref="userDao">

        <!--c:userDao-ref="userDao">-->

    </bean>

        <bean id="accountDao1" class="com.shsxt.dao.AccountDao"

          p:name="cuihua"

          p:age="18">

    </bean>

    <bean id="accountDao2" class="com.shsxt.dao.AccountDao"

          c:name="zhangsan"

          c:age="17">

    </bean>

    <bean id="accountDao3" class="com.shsxt.dao.AccountDao"

          c:_0="lisi"

          c:_1="16">

    </bean>

6、集合注入

xml配置


    <!-- 集合注入 -->

    <bean id="dataService" class="com.shsxt.service.DataService">

        <property name="list">

            <list>

                <value>河南烩面</value>

                <value>南方臊子面</value>

                <value>油泼面</value>

                <value>方便面</value>

            </list>

        </property>

        <property name="set">

            <set>

                <value>快乐小馒头</value>

                <value>北方馒头</value>

                <value>天津麻花</value>

                <value>新疆大饼</value>

            </set>

        </property>

        <property name="map">

            <map>

                <entry>

                    <key><value>河南</value></key>

                    <value>云台山风景</value>

                </entry>

                <entry>

                    <key><value>上海</value></key>

                    <value>宝塔</value>

                </entry>

                <entry>

                    <key><value>北京</value></key>

                    <value>紫禁城</value>

                </entry>

            </map>

        </property>

        <property name="prop">

            <props>

                <prop key="北京">北京尚学堂</prop>

                <prop key="上海">上海尚学堂</prop>

                <prop key="西安">西安尚学堂</prop>

            </props>

        </property>

    </bean>

java类


package com.shsxt.service;

import java.util.List;

import java.util.Map;

import java.util.Properties;

import java.util.Set;

/**

 * Created by xlf on 2019/7/4.

 */

public class DataService {

    private List list;

    private Set set;

    private Map map;

    private Properties prop;

    public void setList(List list) {

        this.list = list;

    }

    public List getList() {

        return list;

    }

    public void setSet(Set set) {

        this.set = set;

    }

    public Set getSet() {

        return set;

    }

    public void setMap(Map map) {

        this.map = map;

    }

    public Map getMap() {

        return map;

    }

    public void setProp(Properties prop) {

        this.prop = prop;

    }

    public Properties getProp() {

        return prop;

    }

    @Override

    public String toString() {

        return "DataService{" +

                "list=" + list +

                ", set=" + set +

                ", map=" + map +

                ", prop=" + prop +

                '}';

    }

}

八、注解方式注入bean

  1. 加入 spring-aop jar包spring-aop-4.3.2.RELEASE.jar
  1. Xml 配置: 加入 context 命名空间 和 xsd地址
  1. 添加 配置

<?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:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="http://www.springframework.org/schema/beans

        http://www.springframework.org/schema/beans/spring-beans.xsd

        http://www.springframework.org/schema/context

        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 开启注解注入配置 -->

    <context:annotation-config/>

</beans>

@Autowired

  • 由spring框架提供

  • 默认通过bean的类型进行匹配

@Resource

  • 由jdk提供

  • 默认通过名字匹配

  • 如果不指定名字,名字为空,则通过类型匹配

tips:推荐使用@Resource注解,属于jdk,减少了与spring的耦合度

九、Spring Ioc 自动扫描管理bean

xml配置


<context:component-scan base-package="com.shsxt"/>

不需要再配置


<context:annotation-config/>

同时对于被 spring管理的bean类的定义上需要加入对应的注解定义

开发中的习惯

  • Dao 层:@Repository

  • Service 层:@Service

  • 视图控制层:@Controller

  • 如果对于开发的类实在不明确到底属于哪个层,可以使用@Component 注解定义。

十、bean的作用域问题

1、singleton作用域

lazy-init 是懒加载, 如果等于 true 时作用是指 spring 容器启动的时候不 会去实例化这个 bean, 而是在程序调用时才去实例化. 默认是 false 即 spring 容器启 动时实例化.

方式一:通过配置


<bean id="userDao" class="com.shsxt.dao.UserDao" lazy-init="true"></bean>

方式二:通过注解@lazy

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

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

2)Bean 对象存在于缓存中,使用时不用再去实例化 bean,加快程序运行效率

什么类型的对象适合作为单例对象来使用呢? service,dao,action 等无状态对象,保证线程的安全性。

一般来说对于无状态或状态不可改变的 对象适合使用单例模式(什么是无状态或状态 不可改变)

实际上对象状态的变化往往均是由于属性值得变化而引起的,比如 user 类 年龄 属性会有变化 属性年龄的变化一般会引起 user 对象状态的变化。对于我们的程序来 说,无状态对象 没有实例变量的存在,保证了线程的安全性,service 层业务对象即是 无状态对象。线程安全的。

prototype作用域

配置文件中通过scope=” prototype”设置 bean 的类型 ,每次向 Spring 容器请求获取 Bean 都返回一个全新的 Bean,相对于“singleton”来说就是不缓存 Bean,每次都是 一个根据 Bean 定义创建的全新 Bean。(不是单例)


例如:

    <bean id="userDao" class="com.shsxt.dao.UserDao" scope="prototype"></bean>

Web应用中的作用域

request 作用域:表示每个请求需要容器创建一个全新 Bean。比如提交表单 的数据必须是对每次请求新建一个 Bean 来保持这些表单数据,请求结束释放这些数据。

session 作用域:表示每个会话需要容器创建一个全新 Bean。比如对于每个用 户一般会有一个会话,该用户的用户信息需要存储到会话中,此时可以将该 Bean 作用 域配置为 session 级别。

globalSession:类似于 session 作用域,其用于 portlet(Portlet 是基于 Java 的 Web 组件,由 Portlet 容器管理,并由容器处理请求,生产动态内容)环境的 web 应 用。如果在非 portlet 环境将视为 session 作用域。

十一、Bean的生命周期

在 Spring 中,Bean 的生命周期包括 Bean 的定义、初始化、使用和销毁 4 个阶段

1、初始化

方式一:


配置文件

<bean id="userDao" class="com.shsxt.dao.UserDao" init-method="init"></bean>

这里init为UserDao里定义的监听方法

方式二:

实现 org.springframework.beans.factory.InitializingBean 接口


package com.shsxt.dao;

import org.springframework.beans.factory.InitializingBean;

/**

 * Created by Administrator on 2019/7/5.

 */

public class UserDao implements InitializingBean{

    public UserDao() {

        //System.out.println("init...");

    }

    public void init(){

        System.out.println("userDao init...");

    }

    @Override

    public void afterPropertiesSet() throws Exception {

        System.out.println("userDao init...22222");

    }

}

2、使用

3、销毁

配置


<bean id="userDao" class="com.shsxt.dao.UserDao" destroy-method="destroy"></bean>

destroy为bean中任意监听方法

测试代码


@Test

    public void test01(){

        AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");

        context.close();

    }

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,084评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,623评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,450评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,322评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,370评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,274评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,126评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,980评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,414评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,599评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,773评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,470评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,080评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,713评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,852评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,865评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,689评论 2 354

推荐阅读更多精彩内容