spring中IOC的简介和使用

什么是spring

spring就是一个管理事务的框架,核心是ioc和aop,不要想象的太复杂,就相当于什么是加法,加法就是用来计算的,核心是数字跟符号。

什么是IOC,IOC有什么作用

IOC又叫控制反转,控制反转(bean标签)的意思就是,生成实例化对象的控制权力反转了,就是生成实例化对象控制的权力发生了变化。以前是直接主动实例化对象,现在是把主动权力给工厂(spring),只能被动的接收。一句话就是,把生成实例化对象的权力给框架或者工厂(spring)。
了解IOC的实现原理才能知道IOC是干嘛的,首先我们介绍工厂模式:工厂模式就是用来生产实例化对象的,为了减少类与类之间的耦合度。
举例:工厂模式的创建对象可以分为单例模式和多例模式,单例模式一般是把所有对象创建在map集合里,用static代码块包裹起来,当加载xml或者properties文件时,在创建工厂时,同时也会创建所有对象。多例模式是指,加载xml方法或者properties方法时,只创建工厂,ID申请一个对象则创建一个对象

**工厂模式简单实现代码:

package com.zxh.bean;
/*
* 第一步:创建properties文件,key=value形式
* 第二步:获取流对象和加载properties文件
* 第三步:使用properties中的key 获取value
* 第四步,使用类加载器,生成对应的对象,返回对象
* */
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
//当类被调用时,Static方法就会直接执行。
public class BeanFactory {
    private  static Properties proper;
    //创建map,当作存放对象的容器。
    private  static Map<String,Object> beans;


    static {
        proper  = new Properties();
        //使用类加载器,获取一个resource的流对象。
        InputStream in =  BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
            //获取properties文件
            proper.load(in);
            //实例化容器对象
            beans=  new HashMap<String,Object>();
            //获取properties中全部的key
            Enumeration keys  = proper.keys();
            //遍历所有的key
            while(keys.hasMoreElements())
            {
                //获取每一个key
                String key = keys.nextElement().toString();
                //根据key获取value
                String beanpath = proper.getProperty(key);
                 //创建value对象
                Object value  = Class.forName(beanpath).newInstance();
                 //把key和value对象存入容器。
                 beans.put(key,value);

            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
//    //根据Bean的名称获取Bean对象(key=value)就是获取可重用组件
        //此方式是,调用一次方法,创建一个对象。多例
//    public  static Object getBean(String beanName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//        Object bean =null;
//        String beanpath = proper.getProperty(beanName);//获取可重用组件的value,也就是全限定类名。
//        bean  =  Class.forName(beanpath).newInstance();//生成beanpath的对象。
//        return bean;
//    }

    //此方式是,先把全部的对象都先创建好放在beans容器中,然后通过key的值来取对象。 单例模式
    public  static Object getBean(String beanName) {
            return beans.get(beanName);
    }
}

工厂模式创建的工厂就相当于IOC容器,就是用来创建对象的,具体流程就是:给我一个id字段 ——工厂生产对象——返回生产的对象。把类与类之间的关系变成了类——工厂——类的关系,实现了编译解耦。

思路:

第一步:不使用new 使用反射。 第二步:通过配置文件,引用配置文件(xml或者properties)。 采用工厂模式。 一个创建Bean对象的工厂 首先创建一个配置文件(key=value),然后再配置文件中写好配置的内容,然后引用配置文件反射到工厂中产生对象。
Bean是可复用的组件,比如JavaBean
但是Bean> JavaBean
JavaBean是指用JAVA语言写的可重用组件,比如实体类。
但是JavaBean>实体类POJO

IOC容器的使用也跟工厂模式差不多

获取spring的IOC容器
1.ApplicationContext构建IOC容器,创建对象的方式采用立即加载,读取完XML后,就已经存在了所有对象,单例对象。
2.BeanFactory构建IOC容器,创建对象采用延迟加载,来一个id(key),生产一个对象(value ),多例对象。
IOC容器是一个map集合,存储的是工厂中产生的对象。
根据ID获取对象
拿到IOC容器
ApplicationContext 有三个常用实现类
ClassPathxmlApplicationContext 加载类路径下的配置文件,要求配置文件必须在类路径下才能加载
FilesysytemxmlApplicationContext 加载磁盘任意位置下的配置文件,必须要有访问权限。
AnnotationConfigAoolicationContext 读取注解创建容器
具体代码

package com.zxh.servlet;


import com.zxh.factory.BeanFactory;
import com.zxh.service.SaveacountService;
import javafx.application.Application;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Test {
    /*
    * 一.获取spring的IOC容器
    *     1.ApplicationContext构建IOC容器,创建对象的方式采用立即加载,读取完XML后,就已经存在了所有对象,单例对象。
    *     2.BeanFactory构建IOC容器,创建对象采用延迟加载,来一个id(key),生产一个对象(value ),多例对象。
    * IOC容器是一个map集合,存储的是工厂中产生的对象。
    * 二.根据ID获取对象
    * */
    public static void main(String[] args){
        //拿到IOC容器
        /*ApplicationContext 有三个常用实现类
        *  ClassPathxmlApplicationContext 加载类路径下的配置文件,要求配置文件必须在类路径下才能加载
        * FilesysytemxmlApplicationContext 加载磁盘任意位置下的配置文件,必须要有访问权限。
        * AnnotationConfigAoolicationContext 读取注解创建容器
        * */
        //        ApplicationContext as = new FileSystemXmlApplicationContext("D:\\intelij\\springframework\\springfirst\\src\\main\\resources\\bean.xml");
        ApplicationContext as = new ClassPathXmlApplicationContext("bean.xml");
        //获取对象
        SaveacountService ss = (SaveacountService) as.getBean("AccountService");
        SaveacountService ss1 = (SaveacountService) as.getBean("AccountService");
        ss.Saveaccount();
        System.out.println(ss);
        System.out.println(ss1);


    }
}

bean的基本配置和使用

<?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">
<!--  把对象创建的控制权交给 spring来管理 -->
<!--   键值对新式-->
<!--   Spirng对Bean的3个管理方面
        一.创建Bean对象的3种方式
            1.使用默认构造函数创建,首先在spring中配置bean标签(可以有多个bean标签),其次属性只有id和class,没有其他的属性和标签
                且类的默认构造方法存在,不然无法使用。
                   <bean id="AccountService" class="com.zxh.serviceimpl.SaveaccountServiceimpl"></bean>
                      <bean id="AccountDao" class="com.zxh.daoimpl.SaveacountDaoimpl"></bean>
            2.使用工厂中(某一个类中)的方法创建对象,存入spring容器。首先获取工厂对象,然后调用工厂对象的方法。
                     <bean id="BeanFactory" class="com.zxh.factory.BeanFactory"></bean>
                      <bean id="AccountService" factory-bean="BeanFactory" factory-method="getBean"></bean>
            3.使用工厂中(某个类中)的静态方法创建对象,存入spring容器
                这一步根本没有创建工厂对象,直接调用static方法。
              <bean id="AccountService" class="com.zxh.factory.BeanFactory" factory-method="getBeanone"></bean>.bean对象的作用范围
            属性标签:scope
            取值:singleton 单例(默认值)
                  prototype 多例模式
                  request 作用于Web应用的请求范围(请求转发,二次请求不可用)
                  session 作用于Web应用的会话范围(重定向,同一个用户的不同请求可用)
                  global-session(跨服务器) 作于于集群环境的会话范围(全局会话范围),不是集群中跟session一样。
        三.bean对象的生命周期
            单例对象(看容器得状态)
                出生:IOC容器创建时对象出生
                存在:容器在则一直存在
                销毁:容器销毁则销毁   destroy-method=""标签。
             多例对象(spring框架)
                出生:spring框架创建
                存在:只要使用就一直活着
                销毁:长时间不使用或者不被引用,则会被垃圾回收器自动回收

-->



```c
在这里插入代码片

以下是spring的依赖注入标签使用

<!--   spring依赖注入
        什么是依赖关系
            就是创建对象的需要用到的其他类。
        什么是依赖注入
            就是把类与类之间的关系转移给spring,类只与spring进行交互。
        依赖关系的管理:
            统一交给交给spring创建,管理和维护,我们只需要在xml中说明。
         注入的数据:
            1.基本类型
            2.bean类型(在xml中或者注解中配置过的类型)
            3.集合类型
          注入的方式:
            1.使用构造函数
            2.使用set方法
            3.使用注解提供

-->

        <!--    构造函数注入
                使用标签:constructor-age
                位置:bean内部
                属性:(key -value)
                    type:指定注入数据类型(int ,string,char),该数据类型是构造函数中的某些数据类型。(一般不用)
                    index:把数据注入到构造函数中相应的索引位置中。(也不要)
                    name:把数据注入到构造函数中指定的属性名称中(用这个)
                    value:需要注入的数据内容。提供基本类型和string
                    ref:需要注入的bean对象。从IOC中拿取已有的bean对象
                缺点:
                    在使用这个bean对象时,必须要注入数据,不然无法创建bean对象。
                       <bean id="AccountService" class="com.zxh.serviceimpl.SaveaccountServiceimpl">
                         <constructor-arg name="name" value="test"></constructor-arg>
                         <constructor-arg name="password" value="123"></constructor-arg>
                     </bean>
        -->
        <!--    set方法注入   依赖注入一般用此方法,能无参注入,也能有参注入.
                    使用标签:property
                    位置:bean内部
                    属性:(key - value)
                          name:指定的是注入时候的方法名。比如setName,只需要写成name="name"
                           value:需要注入的数据内容。提供基本类型和string
                           ref:需要注入的bean对象。从IOC中拿取已有的bean对象
                         <bean id="AccountService" class="com.zxh.serviceimpl.SaveaccountServiceimpl">
                         <property name="name" value="张贤浩"></property>
                          <property name="password" value="123465"></property>
                          </bean>

        -->
            <!--    集合类型注入
            用于list的标签有:list array set
            用于map的标签有:map props
            所有结构相同的标签可以互换
         <bean id="AccountService" class="com.zxh.serviceimpl.SaveaccountServiceimpl">
           <property name=""> name是一个返回类型为list的set方法。
                <list> 还有arry,map,property
                    <value></value>
                    <value></value>
                    <value></value>
              </list>
             </property>
     </bean>


            -->

以下是spring注解开发标签的基本使用

package com.zxh.serviceimpl;


import com.zxh.dao.SaveacountDao;
import com.zxh.service.SaveacountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/*
*
   采用xml配置 <bean id="AccountService" class="com.zxh.serviceimpl.SaveaccountServiceimpl"
   *            scope="" init-method="" destroy-method="">
   *                    <property name="" value="" ref=""></propety>
   *            </bean>
*     采用注解配置
*       用于创建对象的注解
*                   和bean标签一样
*                    @Component
*                           作用:把当前对象注入到spring容器中
*                           属性:
*                               value:指定bean对象的id。默认值是  当前类名  改首字母小写
*                   @Controller------servlet
*                   @Service -----service
*                   @Repository -----dao
*                       以上三个注解,与Component一模一样
*                       是spring提供的三层框架原理,看起来更清晰方便。
*       用于注入数据的注解
*                   和bean标签中property一样(set注入)
*                  @Autowired(不写set方法也可以注入成功!)
*                           作用:按照类型自动注入,但需要容器中有唯一一个bean对象类型和要注入的变量类型配备。
*                                 就是首先需要容器里面有一个对象,且这个对象跟注入的变量类型一样。
*                                  比如你要注入User类型的对象,则你的容器里要有一个User类型的对象,而且是唯一的
*                           位置:可以是变量上,也可以是方法上。
*                            细节:假如有多个User类型,首先会把容器中所有的User类型都选择起来,
*                                   然后根据变量名称去所有User类型中寻找相同的key,如果存在注入成功,不存在报错。
*                   @Qualifier(不能独立使用,必须跟Autowired配合使用)
*                           作用:
*                           属性:
*                                  value:用于按照指定注入的id,注意是指定。
                    @Resource
                            作用: 直接按照bean的id注入,不提托Autowired
                            属性:
                                   name:指定bean的ID
                        ——————————基本类型和Stirng类型不能使用以上注解实现,集合类型的注入只能通过xml实现 ——————————————————————
                    @Value
                    *       作用:用于注入基本类型和String类型的注入
                    *       属性:
                    *           value:需要注入的数据,不是id。可以使用spring的spEL表达式 。value="${表达式}"
* *       用于改变作用范围的
*                   和bean标签中使用scope属性一样。
*                   @Scope
*                          作用:用于指定作用范围
*                          属性:
*                               value:指定范围的取值,有 singleton prototype session golbel-session
*       用于生命周期的
*                   和bean标签中init个destroy一样
*                   @PreDestory:(spring只负责销毁单例对象,不负责多例。)
*                           作用:用于指定销毁方法
*                   @PostConstruct:
*                           作用:用于指定初始化方法
* */

@Component(value="acount")
@Scope(value = "singleton")
public class SaveaccountServiceimpl implements SaveacountService {

    @Autowired()
    @Qualifier("accountdao")
    private SaveacountDao dao;


    public void Saveaccount()
    {

        System.out.println("this is a service");

    }

    @PostConstruct
    public void  init()
    {
        System.out.println("初始化");
    }

    @PreDestroy
    public void destroy()
    {
        System.out.println("销毁");
    }


    public void Saveaccountx()
    {
        dao.saveacount();
    }
}

以下是把配置文件换到class中的注解配置

package com.zxh.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.QueryRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;

/*
* 该类是一个配置类,作用和spring.xml一样的
* spring中的新注解
*       @Configuration
*               作用:指定一个配置类
*       @ComponentScan
*                作用:指定spring创建容器时需要扫描的包 等于
*                       <context:component-scan base-package="com.zxh"></context:component-scan>
*                属性:
*                      value和basePackages 两个属性作用一样.都是指定需要扫描的包
*       @Bean
*               作用:把当前方法的返回值作为bean对象,存入IOC容器 等于
*                   <bean id=""  class=""  ></bean>
*               属性: name
*                     用于指定Bean的ID,默认是当前方法名
*               细节:当使用此注解去配置方法时,如果方法有参数,会自动去容器中找有没有合适的bean对象.跟Autowired一样.
	  @Import
*               作用:用于导入其他配置类
*               属性:
*                   value:用于指定其他配置类的字节码
*                          有import标签的时主配置类,导入的都是子配置类
*      @PropertySource
*              作用:引入properties文件
*              属性:
*                   value:用于指定需要引入的文件名称和路径 value="classpath:xxxx/xxx/xxx/.properties"
*


* */
@Configuration
@ComponentScan(value = "com.zxh")
public class configuration {

    /*
    * guang
    * */
    @Bean(name = "queryrunner")
    public QueryRunner CreateQuery(DataSource datasource)
    {
        return  new QueryRunner(datasource);
    }

    /*
    * 创建数据源对象
    *
    * */
    @Bean(name = "datasource")
    public DataSource Createsource()  {

        try {
            ComboPooledDataSource ds  =  new ComboPooledDataSource();
            ds.setDriverClass("com.mysql.jdbc.Driver");
            ds.setJdbcUrl("jdbc:mysql://localhost:3306/spring");
            ds.setUser("root");
            ds.setPassword("root");
            return  ds;
        } catch (PropertyVetoException e) {
            throw  new RuntimeException(e);
        }


    }
}

总结

学习spring,我们首先要了解spring是用来干嘛的,然后再去了解工厂模式,接着类比工厂模式去理解IOC的的作用和spring的作用,然后学会使用spring xml标签的配置和在类中与IOC容器交互的方法。

发布了5 篇原创文章 · 获赞 2 · 访问量 339

猜你喜欢

转载自blog.csdn.net/weixin_43881925/article/details/104515981
今日推荐