spring第一天IOC

自己实现类似于spring IOC的功能(以后再深入单例与多例对象,解耦),通过工厂方式调用资源,容器的概念,以及使用spring管理容器,spring容器管理的细节,创建bean的三种方式,bean对象的生命周期,依赖注入的三种方式

实现类似于spring IOC的功能

  • spring IOC:控制反转,实际上就是为了解耦合,
    在开发中,通常通过service层调用dao层,业务层调用持久层,并且此时业务层在依赖持久层的接口和实现类。如果此时没有持久层实现类,编译将不能通过。这种编译期依赖关系,应该在我们开发中杜绝。我们需要优化代码解决。
    实际上就是减少用new来创建对象
  • 当是我们使用jdbc 时,是通过反射来注册驱动的 :
    Class.forName(“com.mysql.jdbc.Driver”);//此处只是一个字符串
    这时候如果数据库改用Oracle了,只需改掉该字符串,
  • 同时,也产生了一个新的问题,mysql 驱动的全限定类名字符串是在 java 类中写死的,一旦要改还是要修改源码。
  • 解决这个问题也很简单,使用配置文件配置。

在resource包中创建一个文件bean.properties,

accountService=com.service.IAccountService
accountDao=com.dao.IAccountDao

配置文件中存储形式为key,value的形式,前为名称,后为全限定类名

  • 在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。
    这其实就是工厂模式,这个读取配置文件,创建和获取三层对象的类(BeanFactory)就是工厂

在这里插入图片描述
不直接new对象,而是通过工厂提供资源。
在这里插入图片描述

public class BeanFactory {
	//用于读取配置文件
    public static Properties pro;

    //定义一个map,用于存放我们要创建的对象,称之为容器
    public static Map<String,Object> beans;

    static{
        try {
            pro = new Properties();
            //通过类加载器加载配置文件中的流
            InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
            pro.load(in);
            //实例化容器 
            beans = new HashMap<String, Object>();
            //取出配置文件中所有的key
            Enumeration  keys = pro.keys();
            while(keys.hasMoreElements()){
                //取出每个key
                String key = keys.nextElement().toString();
                //根据key获取value
                String beanPath = pro.getProperty(key);
                //反射创建对象
                Object value = Class.forName(beanPath).newInstance();
                beans.put(key,value);

            }
        }catch (Exception e){
            throw new ExceptionInInitializerError("初始化bean.properties失败!");
        }

    }

    public static Object getBean(String beanName){
        return beans.get(beanName);
    } 
}

现在通过工厂就可以获得accountDao和accountService对象了。

/**
 * 模拟一个表现层,用于调用业务层
 */
public class Client {

    public static void main(String[] args) {
        //IAccountService as = new AccountServiceImpl();
        for(int i=0;i<5;i++) {
            IAccountService as = (IAccountService) BeanFactory.getBean("accountService");
            System.out.println(as);
            as.saveAccount();
        }

    }
}

所以在测试类中,不用通过new来获得accountService的实现类了。

使用spring管理容器

基于xml的配置

在这里插入图片描述
通过maven创建工程,在pom.xml中引入spring依赖

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.0.2.RELEASE</version>
    </dependency>
</dependencies>

然后创建bean.xml,这次通过spring管理容器
首先引入xsd约束,然后将对象注入容器

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

    <bean id="accountService" class="com.service.impl.AccountServiceImpl"></bean>
    <bean id="accountDao" class="com.dao.impl.AccountDaoImpl"></bean>
</beans>
public class Client {
    /**
     * 获取spring容器的ioc容器,并根据id获取对象
     * @param args
     */
    public static void main(String[] args) {
        //获取核心容器对象
          ApplicationContext app = new ClassPathXmlApplicationContext("bean.xml");
        //根据id获取bean对象
        IAccountService ias = (IAccountService)app.getBean("accountService");
        IAccountDao iad = app.getBean("accountDao",IAccountDao.class);
        System.out.println(ias);
        System.out.println(iad);
    }
}

此时就可以得到accountDao和accountService对象了,以上使用两种方法获取。

spring对bean的管理细节

创建Bean的三种方式

  • 第一种方式:使用默认构造函数创建。
    在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
    采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。
<bean id="accountService" class="com.service.impl.AccountServiceImpl" scope="singleton" init-method="init" destroy-method="destroy"></bean>

其中scope="singleton"指单例对象,多例则指定为prototype,init-method=“init” destroy-method="destroy"则指定从bean.xml获取到的AccountServiceImpl 类中的init()和destory()方法

public class AccountServiceImpl implements IAccountService {

    //使用spring的第一种使用默认构造函数构造bean的方法,因为重写了构造函数,所以没有默认构造,报错
    //    public AccountServiceImpl(String name){Failed to instantiate [com.service.impl.AccountServiceImpl]: No default constructor found;
//    public AccountServiceImpl(String name){
//        System.out.println("对象创建了");
//    }
	//默认构造函数
    public AccountServiceImpl(){
        System.out.println("对象创建了");
    }
    public void  saveAccount(){
        System.out.println("service中的saveAccOunt执行了");

    }
    public void  init(){
        System.out.println("对象初始化了。。。");
    }
    public void  destroy(){
        System.out.println("对象销毁了。。。");
    }
}
  • 第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
<bean id="instanceFactory" class="com.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
/**
 * 模拟一个工厂类(该类可能是存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数)
 */
public class InstanceFactory {

    public IAccountService getAccountService(){
        return new AccountServiceImpl();
    }
}
  • 第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
    <bean id="accountService" class="com.factory.StaticFactory" factory-method="getAccountService"></bean>
/**
 * 模拟一个工厂类(该类可能是存在于jar包中的,我们无法通过修改源码的方式来提供默认构造函数)
 */
public class StaticFactory {

    public static IAccountService getAccountService(){

        return new AccountServiceImpl();
    }
}
spring的依赖注入

Dependency Injection
IOC的作用:
降低程序间的耦合(依赖关系)
依赖关系的管理:
以后都交给spring来维护
在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明
依赖关系的维护:
就称之为依赖注入。

         注入的方式:有三种
  • 第一种:使用构造函数提供
    构造函数注入:
    使用的标签:constructor-arg
    标签出现的位置:bean标签的内部
    标签中的属性
    type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
    index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始
    name:用于指定给构造函数中指定名称的参数赋值 常用的
    以上三个用于指定给构造函数中哪个参数赋值
    value:用于提供基本类型和String类型的数据
    ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象

     优势:
         在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
     弊端:
         改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
    

能注入的数据:有三类
基本类型和String
其他bean类型(在配置文件中或者注解配置过的bean)
复杂类型/集合类型

<bean id="accountService" class="com.service.impl.AccountServiceImpl">
        <constructor-arg name="age" value="18"></constructor-arg>
        <constructor-arg name="name" value="lin"></constructor-arg>
        <constructor-arg name="birthday" ref="1997-1-1"></constructor-arg>
    </bean>

日期注入就要用在配置文件配置过的bean来注入

<!-- 读取全限定类名,通过反射创建一个对象,并且存入spring容器中,可通过id将其取出    -->
    <bean id="now" class="java.util.Date"></bean>
  • 第二种:使用set方法提供
    涉及的标签:property
    出现的位置:bean标签的内部
    标签的属性
    name:用于指定注入时所调用的set方法名称
    value:用于提供基本类型和String类型的数据
    ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
    优势:
    创建对象时没有明确的限制,可以直接使用默认构造函数
    弊端:
    如果有某个成员必须有值,则获取对象是有可能set方法没有执行。

set方法就要在class属性中的类中生成set方法

public class AccountServiceImpl implements IAccountService { 
    //如果是经常变化的数据,并不适用于注入的方式 
    private String name;
    private Integer age;
    private Date birthday; 

    //set方法注入
    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public void  saveAccount(){
        System.out.println("service中的saveAccount方法执行了。。。"+name+" "+age+"  "+birthday);
    }
 
}
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
        <property name="age" value="18"></property>
        <property name="birthday" ref="now"></property>
        <property name="name" value="test"></property>
    </bean>

也可以用set方法注入复杂类型(list,map等)

  • 复杂类型的注入/集合类型的注入
    用于给List结构集合注入的标签:
    list array set
    用于个Map结构集合注入的标签:
    map props
    结构相同(指key,value结构),标签可以互换
public class AccountServiceImpl2 implements IAccountService {

    private String[] myStrs;
    private List<String> myList;
    private Set<String> mySet;
    private Map<String,String> myMap;
    private Properties properties; 
    public void setMyStrs(String[] myStrs) {
        this.myStrs = myStrs;
    } 
    public void setMyList(List<String> myList) {
        this.myList = myList;
    } 
    public void setMySet(Set<String> mySet) {
        this.mySet = mySet;
    } 
    public void setMyMap(Map<String, String> myMap) {
        this.myMap = myMap;
    } 
    public void setProperties(Properties properties) {
        this.properties = properties;
    } 
    public void  saveAccount(){
        System.out.println(Arrays.toString(myStrs));
        System.out.println(myList);
        System.out.println(myMap);
        System.out.println(mySet);
        System.out.println(properties); 
    } 
}
 <bean id="accountService2" class="com.itheima.service.impl.AccountServiceImpl2">
        <property name="myStrs">
            <array>
                <value>AAA</value>
                <value>CCC</value>
                <value>BBB</value>
            </array>
        </property>
        <property name="myMap">
            <map>
                <entry key="test1" value="aaa"></entry>
                <entry key="test2" value="bbb"></entry>
            </map>
        </property>
        <property name="myList">
            <list>
                <value>AAA</value>
                <value>CCC</value>
                <value>BBB</value>
            </list>
        </property>
    </bean>
  • 第三种:使用注解提供

基于注解形式创建

见第二天

发布了19 篇原创文章 · 获赞 4 · 访问量 1245

猜你喜欢

转载自blog.csdn.net/weixin_43427728/article/details/104065521