SpringDay1

一、Spring相关概念

1.1、Spring架构图

Core Container:核心容器,这个模块是Spring最核心的模块,其他的都需要依赖该模块。
AOP:面向切面编程,它依赖核心层容器,目的是在不改变原有代码的前提下对其进行功能增强
Aspects:AOP是思想,Aspects是对AOP思想的具体实现。
Data Access:数据访问,Spring全家桶中有对数据访问的具体实现技术。
Data Integration:数据集成,Spring支持整合其他的数据层解决方案,比如Mybatis。
Transactions:事物,事务管理是Spring AOP的一个具体实现,也是后期学习的重点内容。
Web层:这一层的内容将在SpringMVC框架具体学习。
Test层:Spring主要整合了Junit来完成单元测试和集成测试。

1.2 背景

以前项目存在的问题:

(1)业务层需要调用数据层的方法,就需要在业务层new数据层的对象
(2)如果数据层的实现类发生变化,那么业务层的代码也需要跟着改变,发生变更后,都需要进行编译打包和重部署
(3)所以,现在代码在编写的过程中存在的问题是:耦合度偏高

如何解决这个问题?

        我们就想,如果能把框中的内容给去掉,不就可以降低依赖了么,但是又会引入新的问题,去掉以后 程序能运行么?
        答案肯定是不行,因为bookDao没有赋值为 Null ,强行运行就会出空指针异常。

        所以现在的问题就是,业务层不想new对象,运行的时候又需要这个对象,该咋办呢?
        针对这个问题,Spring就提出了一个解决方案:
        使用对象时,在程序中不要主动使用new产生对象,转换为由
外部提供对象。
        这种实现思想就是Spring的一个核心概念。

1.3 IOC/DI概念

IOC(Inversion of Control)控制反转/DI(Dependency Injection)依赖注入.

(1)什么是控制反转呢?

        使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转。

(2)Spring和IOC之间的关系是什么呢?

        Spring技术对IOC思想进行了实现
        Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的"外部"
        IOC思想中的[外部]指的就是Spring的IOC容器

(3)IOC容器的作用以及内部存放的是什么?

        IOC容器负责对象的创建、初始化等一系列工作,其中包含了数据层和业务层的类对象
        被创建或被管理的对象在IOC容器中统称为Bean
        IOC容器中放的就是一个个的Bean对象

(4)当IOC容器中创建好service和dao对象后,程序能正确执行么?

        不行,因为service运行需要依赖dao对象
        IOC容器中虽然有service和dao对象,但是service对象和dao对象没有任何关系
        需要把dao对象交给service,也就是说要绑定service和dao对象之间的关系,就用到了DI。

(5)什么是依赖注入呢?

        在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
        业务层要用数据层的类对象,以前是自己new的现在自己不new了,靠别人[外部其实指的就是IOC容器]来给注入进来。

(6)IOC容器中哪些bean之间要建立依赖关系呢?

        这个需要程序员根据业务需求提前建立好关系,如业务层需要依赖数据层,service就要和dao建立依赖关系.

介绍完Spring的IOC和DI的概念后,我们会发现这两个概念的最终目标就是:充分解耦

具体实现为:使用IOC容器管理bean(IOC);在IOC容器内将有依赖关系的bean进行关系绑定(DI)。最终结果为:使用对象时不仅可以直接从IOC容器中获取,并且获取到的bean已经绑定了所有的依赖关系。

控制反转代码演示:

1.创建Maven的java项目(略)

2.pom.xml添加Spring的依赖jar包(略)

3.创建BookService,BookServiceImpl,BookDao和BookDaoImpl四个类

public interface BookDao { 
    public void save(); 
}

public class BookDaoImpl implements BookDao { 
    public void save() { 
        System.out.println("book dao save ..."); 
    } 
}

public interface BookService { 
    public void save(); 
}

public class BookServiceImpl implements BookService { 
    private BookDao bookDao = new BookDaoImpl(); 
    public void save() { 
        System.out.println("book service save ..."); 
        bookDao.save(); 
    }
}

4.resources下添加spring配置文件applicationContext.xml,并完成bean的配置

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> 
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"/>

5.使用Spring提供的接口完成IOC容器的创建;从容器中获取对象进行方法调用

public class App { 
    public static void main(String[] args) { 
        //获取IOC容器 
        ApplicationContext ctx = new 
ClassPathXmlApplicationContext("applicationContext.xml"); 
        //从容器中获取对象进行方法调用
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    } 
}

依赖注入代码演示(IOC代码基础上修改)

5.删除业务层中使用new的方式创建的dao对象
6.在业务层提供BookDao的setter方法
7.在配置文件中添加依赖注入的配置

public class BookServiceImpl implements BookService { 
    //5.删除业务层中使用new的方式创建的dao对象
    //private BookDao bookDao = new BookDaoImpl(); 
    private BookDao bookDao;
    public void save() { 
        System.out.println("book service save ..."); 
        bookDao.save(); 
    }
    //6.提供对应的set方法 
    public void setBookDao(BookDao bookDao) { 
        this.bookDao = bookDao; 
    }
}

4.resources下添加spring配置文件applicationContext.xml,并完成bean的配置
<!--private BookDao bookDao = new BookDaoImpl()-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> 
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"/>
    <!--7.配置server与dao的关系-->
    <property name="bookDao" ref="bookDao"/>
    <!--property标签表示配置当前bean的属性 
        name属性表示配置哪一个具体的属性 
        ref属性表示参照哪一个bean -->

name="bookDao"中bookDao指的是一个名称为bookDao的属性;
将首字母大写,前面加set去找对应的setBookDao()方法。

ref="bookDao"中bookDao指的是一个id为bookDao的Bean对象;
这个对象充当set方法的参数,给bookService的属性进行注入。

5.使用Spring提供的接口完成IOC容器的创建;从容器中获取对象进行方法调用

public class App { 
    public static void main(String[] args) { 
        //获取IOC容器 
        ApplicationContext ctx = new 
ClassPathXmlApplicationContext("applicationContext.xml"); 
        //从容器中获取对象进行方法调用
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    } 
}

二、Bean管理

2.1 Bean基础配置

class 属性能不能写接口如 BookDao 的类全名呢 ?
        答案肯定是不行,因为接口是没办法创建对象的。
前面提过为 bean 设置 id 时, id 必须唯一,但是如果由于命名习惯而产生了分歧后,该如何解决 ?

        给Bean配置别名;获取Bean对象时可以用别名。

bean 依赖注入的 ref 属性指定 bean必须在容器中存在,不存在 会报NoSuchBeanDefinitionException

2.2 Bean作用范围

为什么Spring创建的bean对象默认都是单例的?

        bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象
        bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高。

bean在容器中是单例的,会不会产生线程安全问题?

        如果对象是有状态对象,即该对象有成员变量可以用来存储数据的,因为所有请求线程共用一个bean对象,所以会存在线程安全问题。
        如果对象是无状态对象,即该对象没有成员变量没有进行数据存储的,因方法中的局部变量在方法调用完成后会被销毁,所以不会存在线程安全问题。

哪些bean对象适合交给容器进行管理?

        表现层对象、业务层对象、数据层对象、工具对象。

哪些bean对象不适合交给容器进行管理?

        封装实例的域对象,因为会引发线程安全问题,所以不适合。

2.3 Bean的实例化

Bean有三种实例化方式:构造方法,静态工厂和实例工厂。

(1)构造方法实例化

//1.准备两个类
public interface BookDao { 
    public void save(); 
}

public class BookDaoImpl implements BookDao { 
    //4.1、类中提供构造函数测试
    public BookDaoImpl() { 
        System.out.println("book dao constructor is running ...."); 
    }
    //4.2、构造函数中添加一个参数测试
    /*private BookDaoImpl(int i) { 
        System.out.println("book dao constructor is running ...."); 
    }*/
    //4.3、将构造函数改成private测试
    /*private BookDaoImpl() { 
        System.out.println("book dao constructor is running ...."); 
    }*/
    public void save() { 
        System.out.println("book dao save ..."); 
    } 
}

//2.将类配置到Spring容器applicationContext.xml
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>

//3.编写运行程序
public class App { 
    public static void main(String[] args) {   
        ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml"); 
        BookDao bookDao = (BookDao) ctx.getBean("bookDao"); 
        bookDao.save();
    } 
}

4.1运行程序,控制台有打印构造函数中的输出,说明Spring容器创建对象时走的是构造函数
4.2运行程序,同样能执行成功,说明内部走的依然是构造函数,能访问到类中的私有构造方法
4.3运行程序,程序会报错,说明Spring底层使用的是类的无参构造方法。

(2)静态工厂实例化

//1、准备一个OrderDao和OrderDaoImpl类
public interface OrderDao { 
    public void save(); 
}

public class OrderDaoImpl implements OrderDao { 
    public void save() { 
        System.out.println("order dao save ..."); 
    } 
}
//2、创建一个工厂类OrderDaoFactory并提供一个静态方法
public class OrderDaoFactory { 
    public static OrderDao getOrderDao(){ 
        return new OrderDaoImpl(); 
    } 
}
//3、编写AppForInstanceOrder运行类,在类中通过工厂获取对象
public class AppForInstanceOrder { 
    public static void main(String[] args) { 
        //通过静态工厂创建对象 
        OrderDao orderDao = OrderDaoFactory.getOrderDao(); 
        orderDao.save(); 
    } 
}

//上面第3步在Spring中换为3.1+3.2
//3.1、将静态工厂类配置到Spring容器applicationContext.xml
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" 
factory- method="getOrderDao"/>
//3.2、编写AppForInstanceOrder运行类,在类中通过IOC容器获取对象
public class AppForInstanceOrder {
    public static void main(String[] args) {   
        ApplicationContext ctx = new 
ClassPathXmlApplicationContext("applicationContext.xml"); 
        OrderDao orderDao = (OrderDao) ctx.getBean("orderDao"); 
        orderDao.save();
    }
}

        在工厂的静态方法中,我们除了new对象还可以做其他的一些业务操作,而之前new对象的方式就无法添加其他的业务内容

 (3)实例工厂实例化

//1、准备一个UserDao和UserDaoImpl类
public interface UserDao { 
    public void save(); 
}
public class UserDaoImpl implements UserDao { 
    public void save() {
        System.out.println("user dao save ..."); 
    } 
}
//2、创建一个工厂类UserDaoFactory,并提供一个普通方法,非静态方法
public class UserDaoFactory { 
    public UserDao getUserDao(){ 
        return new UserDaoImpl(); 
    } 
}
//3、编写AppForInstanceUser运行类,在类中通过工厂获取对象
public class AppForInstanceUser { 
    public static void main(String[] args) { 
        //创建实例工厂对象 
        UserDaoFactory userDaoFactory = new UserDaoFactory(); 
        //通过实例工厂对象创建对象 
        UserDao userDao = userDaoFactory.getUserDao(); 
        userDao.save(); 
    }
}
//上面第3步在Spring中换为3.1+3.2
//3.1、在spring的配置文件中添加以下内容:
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/> 
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

//3.2、在AppForInstanceUser运行类,使用从IOC容器中获取bean的方法
public class AppForInstanceUser { 
    public static void main(String[] args) { 
        ApplicationContext ctx = new 
ClassPathXmlApplicationContext("applicationContext.xml"); 
        UserDao userDao = (UserDao) ctx.getBean("userDao"); 
        userDao.save(); 
    } 
}

 (4)实例化工厂改进

//1、不做修改
//2、创建一个FactoryBean代替工厂类
public class UserDaoFactoryBean implements FactoryBean<UserDao> { 
    //代替原始实例工厂中创建对象的方法 
    public UserDao getObject() throws Exception { 
        return new UserDaoImpl(); 
    }
    //返回所创建类的Class对象 
    public Class<?> getObjectType() { 
        return UserDao.class; 
    } 
    /*public boolean isSingleton() { 
        return true; 
    }*/
}
//3.1、在spring的配置文件中添加以下内容:
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

//3.2、AppForInstanceUser运行类不用做任何修改,直接运行

区别:简化配置文件内容

<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/> 
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
VS
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>

2..4 Bean的生命周期

首先理解下什么是生命周期?

        从创建到消亡的完整过程,例如人从出生到死亡的整个过程就是一个生命周期。

bean生命周期是什么?

        bean对象从创建到销毁的整体过程。

bean生命周期控制是什么?

        在bean创建后到销毁前做一些事情。

        那么我们考虑的问题是如何在bean的创建之后和销毁之前把我们需要添加的内容添加进去。

环境准备:

创建一个Maven项目

pom.xml添加依赖

resources下添加spring的配置文件applicationContext.xml;与前面一致。

//1.项目中添加BookDao、BookDaoImpl、BookService和BookServiceImpl类
public interface BookDao { 
    public void save(); 
}

public class BookDaoImpl implements BookDao { 
    public void save() { 
        System.out.println("book dao save ..."); 
    } 
    //表示bean初始化对应的操作 
    public void init(){ 
        System.out.println("init..."); 
    }
    //表示bean销毁前对应的操作 
    public void destory(){ 
    System.out.println("destory..."); 
    }
}

public interface BookService { 
    public void save(); 
}

public class BookServiceImpl implements BookService{ 
    private BookDao bookDao; 
    public void setBookDao(BookDao bookDao) { 
        this.bookDao = bookDao; 
    }
    public void save() { 
        System.out.println("book service save ..."); 
        bookDao.save();
    }
}

//2.resources下提供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"> 
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/> 
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> 
        <property name="bookDao" ref="bookDao"/> 
    </bean>
</beans>

//3.编写AppForLifeCycle运行类,加载Spring的IOC容器,并从中获取对应的bean对象
public class AppForLifeCycle { 
    public static void main( String[] args ) { 
        ApplicationContext ctx = new 
ClassPathXmlApplicationContext("applicationContext.xml"); 
        BookDao bookDao = (BookDao) ctx.getBean("bookDao"); 
        bookDao.save(); 
    } 
}

运行程序:
init...
book dao save...

init方法执行了,但是destroy方法却未执行,这是为什么呢?
Spring的IOC容器是运行在JVM中
运行main方法后,JVM启动,Spring加载配置文件生成IOC容器,从容器获取bean对象,然后调方法执行
main方法执行完后,JVM退出,这个时候IOC容器中的bean还没有来得及销毁就已经结束了
所以没有调用对应的destroy方法

方法一:将ApplicationContext更换成ClassPathXmlApplicationContext,调用其close方法
ClassPathXmlApplicationContext ctx = new
    ClassPathXmlApplicationContext("applicationContext.xml");
ctx.close();

运行程序:
init...
book dao save...
destory...

方法二:更换成ClassPathXmlApplicationContext,调用registerShutdownHook()方法
ctx.registerShutdownHook();
也会执行destory()

close和registerShutdownHook区别?
close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭。

        分析上面的实现过程,会发现添加初始化和销毁方法,即需要编码也需要配置,实现起来步骤比较多也比较乱。
        Spring提供了两个接口来完成生命周期的控制,好处是可以不用再进行配置init-method和 destroy-method

        修改BookServiceImpl类,添加两个接口InitializingBean, DisposableBean并实现接口中的
两个方法afterPropertiesSet和destroy

public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    private BookDao bookDao; 
    public void setBookDao(BookDao bookDao) { 
        System.out.println("set ...");
        this.bookDao = bookDao; 
    }
    public void save() { 
        System.out.println("book service save ..."); 
        bookDao.save(); 
    }
    public void destroy() throws Exception { 
        System.out.println("service destroy"); 
    }
    public void afterPropertiesSet() throws Exception { 
        System.out.println("service init"); 
    } 
}

重新运行AppForLifeCycle类:
init...
set...
service init
book dao save...
service destroy
destory...

三、DI操作

思考:

向一个类中传递数据的方式有几种?

        普通方法(set方法)
        构造方法

传递数据的类型包括哪些呢?

        引用类型
        简单类型(基本数据类型与String)

Spring就是基于上面这些知识点,为我们提供了两种注入方式,分别是:

        setter注入:简单类型、引用类型。

        构造器注入:简单类型、引用类型。

3.1 Setter注入

环境搭建:

创建一个Maven项目

pom.xml添加依赖

resources下添加spring的配置文件applicationContext.xml;与前面一致。

//1.项目中添加BookDao、BookDaoImpl、UserDao、UserDaoImpl、BookService和BookServiceImpl类
public interface BookDao { 
    public void save(); 
}
public class BookDaoImpl implements BookDao { 
    public void save() { 
        System.out.println("book dao save ..."); 
    } 
}

public interface UserDao { 
    public void save(); 
}
public class UserDaoImpl implements UserDao { 
    public void save() { 
        System.out.println("user dao save ..."); 
    } 
}

public interface BookService { 
    public void save(); 
}
public class BookServiceImpl implements BookService{ 
    private BookDao bookDao; 
    public void setBookDao(BookDao bookDao) { 
        this.bookDao = bookDao; 
    }
    public void save() { 
        System.out.println("book service save ..."); 
        bookDao.save();
    }
}

//2.resources下提供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"> 
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> 
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> 
        <property name="bookDao" ref="bookDao"/> 
    </bean> 
</beans>

//3.编写AppForDISet运行类,加载Spring的IOC容器,并从中获取对应的bean对象
public class AppForDISet{ 
    public static void main( String[] args ) { 
        ApplicationContext ctx = new 
ClassPathXmlApplicationContext("applicationContext.xml"); 
        BookDao bookService= (BookService) ctx.getBean("bookService"); 
        bookService.save(); 
    } 
}

运行程序
book service save ...
book dao save ...

3.1.1 注入引用数据类型

需求:在bookServiceImpl对象中注入userDao

1.在BookServiceImpl中声明userDao属性,并提供Setter方法
public class BookServiceImpl implements BookService{ 
    private BookDao bookDao; 
    private UserDao userDao; 
    public void setUserDao(UserDao userDao) { 
        this.userDao = userDao; 
    }
    public void setBookDao(BookDao bookDao) { 
        this.bookDao = bookDao; 
    }
    public void save() { 
        System.out.println("book service save ..."); 
        bookDao.save(); 
        userDao.save(); 
    } 
}

2.在配置文件中使用property标签注入
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> 
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> 
        <property name="bookDao" ref="bookDao"/> 
        <property name="userDao" ref="userDao"/>
    </bean> 
</beans>

3.运行程序
book service save ...
book dao save ...
user dao save ...

3.1.2 注入简单数据类型

需求:在BookDaoImpl对象中注入简单数据类型

1.在BookServiceImpl中声明声明对应的简单数据类型的属性,并提供对应的setter方法
public class BookDaoImpl implements BookDao{ 
    private String databaseName; 
    private int connectionNum; 
    public void setConnectionNum(int connectionNum) { 
        this.connectionNum = connectionNum; 
    }
    public void setDatabaseName(String databaseName) { 
        this.databaseName = databaseName; 
    }
    public void save() { 
        System.out.println("book dao save ..."+databaseName+","+connectionNum); 
    }
}

2.在配置文件中使用property标签注入
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> 
        <property name="databaseName" value="mysql"/> 
        <property name="connectionNum" value="10"/> 
    </bean>
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> 
        <property name="bookDao" ref="bookDao"/> 
        <property name="userDao" ref="userDao"/>
    </bean> 
</beans>
//value:后面跟的是简单数据类型,对于参数类型,Spring在注入的时候会自动转换

3.运行程序
book service save ...
book dao save ...mysql,10
user dao save ...

3.2 构造器注入

//1.项目中添加BookDao、BookDaoImpl、UserDao、UserDaoImpl、BookService和BookServiceImpl类
public interface BookDao { 
    public void save(); 
}
public class BookDaoImpl implements BookDao {
    private String databaseName; 
    private int connectionNum;  
    public void save() { 
        System.out.println("book dao save ..."); 
    } 
}

public interface UserDao { 
    public void save(); 
}
public class UserDaoImpl implements UserDao { 
    public void save() { 
        System.out.println("user dao save ..."); 
    } 
}

public interface BookService { 
    public void save(); 
}
public class BookServiceImpl implements BookService{ 
    private BookDao bookDao; 
    public void setBookDao(BookDao bookDao) { 
        this.bookDao = bookDao; 
    }
    public void save() { 
        System.out.println("book service save ..."); 
        bookDao.save();
    }
}

//2.resources下提供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"> 
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> 
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> 
        <property name="bookDao" ref="bookDao"/> 
    </bean> 
</beans>

//3.编写AppForDIConstructor运行类,加载Spring的IOC容器,并从中获取对应的bean对象
public class AppForDIConstructor{ 
    public static void main( String[] args ) { 
        ApplicationContext ctx = new 
ClassPathXmlApplicationContext("applicationContext.xml"); 
        BookDao bookService= (BookService) ctx.getBean("bookService"); 
        bookService.save(); 
    } 
}

3.2.1 注入引用数据类型

需求:将BookServiceImpl类中的bookDao修改成使用构造器的方式注入。

1.在BookServiceImpl类中将bookDao的setter方法删除掉,并添加带有bookDao参数的构造方法
public class BookServiceImpl implements BookService{ 
    public BookServiceImpl(BookDao bookDao,UserDao userDao) { 
        this.bookDao = bookDao; 
        this.userDao = userDao; 
    }
    public void save() { 
        System.out.println("book service save ..."); 
        bookDao.save(); 
        userDao.save();
    } 
}

2.在applicationContext.xml中配置
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> 
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> 
        <constructor-arg name="bookDao" ref="bookDao"/> 
        <constructor-arg name="userDao" ref="userDao"/>
    </bean> 
</beans>

3.运行程序
book service save ...
book dao save ...
user dao save ...

3.2.2 注入简单数据类型

需求:在BookDaoImpl中,使用构造函数注入databaseName和connectionNum两个参数。

1.提供一个包含这两个参数的构造方法
public class BookDaoImpl implements BookDao {
    private String databaseName; 
    private int connectionNum;  

    public BookDaoImpl(String databaseName, int connectionNum) { 
        this.databaseName = databaseName; 
        this.connectionNum = connectionNum; 
    }
    public void save() { 
        System.out.println("book dao save..."+databaseName+","+connectionNum);
}

2.在applicationContext.xml中进行注入配置
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> 
        <constructor-arg name="databaseName" value="mysql"/> 
        <constructor-arg name="connectionNum" value="666"/>
    <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"/>
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> 
        <constructor-arg name="bookDao" ref="bookDao"/> 
        <constructor-arg name="userDao" ref="userDao"/>
    </bean> 
</beans>

3.运行程序
book service save ...
book dao save ...mysql,666
user dao save ...
        当构造函数中方法的参数名发生变化后,配置文件中的name属性也需要跟着,这两块存在紧耦合,具体该如何解决 ?
方法一:删除name属性,添加type属性,按照类型注入
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> 
    <constructor-arg type="int" value="10"/> 
    <constructor-arg type="java.lang.String" value="mysql"/> 
</bean>
但是如果构造方法参数中有类型相同的参数,这种方式就不太好实现

方法二:删除type属性,添加index属性,按照索引下标注入,下标从0开始
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> 
    <constructor-arg index="1" value="100"/> 
    <constructor-arg index="0" value="mysql"/> 
</bean>
但是如果构造方法参数顺序发生变化后,这种方式又带来了耦合问题

介绍完两种参数的注入方式,具体我们该如何选择呢? 

1. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现(强制依赖指对象在创建的过程中必须要注入指定的参数)

2. 可选依赖使用setter注入进行灵活性强(可选依赖指对象在创建过程中注入的参数可有可无)

3. Spring框架倡导使用构造器,第三方框架大多数采用构造器注入的形式进行数据初始化。

4. 两者同时使用时,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入

5. 自己开发的模块推荐使用setter注入

3.3 自动配置

Setter注入方式中配置文件的编写上有更简单的方式:自动装配。

自动装配:IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配

自动装配:按类型(byType)按名称(byName)按构造器装配(不推荐用)

环境构造(Setter注入那块代码)

(1)将<property>标签删除
(2)在<bean>标签中添加autowire属性

<?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唯一-->
    <bean class="com.itheima.dao.impl.BookDaoImpl"/> 
    <!--autowire属性:开启自动装配,通常使用按类型装配--> 
    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/> 
</beans>

运行程序
book service save ...
book dao save ...

1. 自动装配用于引用类型依赖注入,不能对简单类型进行操作
2. 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
3. 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
4. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

 3.4 集合注入

        前面我们已经能完成引入数据类型和简单数据类型的注入,但是还有一种数据类型集合,集合中既可以装简单数据类型也可以装引用数据类型,对于集合,在Spring中该如何注入呢?

环境准备:

1.项目中添加添加BookDao、BookDaoImpl类
public interface BookDao { 
    public void save(); 
}
public class BookDaoImpl implements BookDao { 
    private int[] array; private List<String> list; 
    private Set<String> set; 
    private Map<String,String> map; 
    private Properties properties; 
    public void save() {
        System.out.println("book dao save ..."); 
        System.out.println("遍历数组:" + Arrays.toString(array)); 
        System.out.println("遍历List" + list); 
        System.out.println("遍历Set" + set); 
        System.out.println("遍历Map" + map); 
        System.out.println("遍历Properties" + properties); 
    }//setter....方法省略,自己使用工具生成 
}

2.resources下提供spring的配置文件,applicationContext.xml
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> 
</beans>

3.编写AppForDICollection运行类,加载Spring的IOC容器,并从中获取对应的bean对象
public class AppForDICollection { 
    public static void main( String[] args ) { 
        ApplicationContext ctx = new 
ClassPathXmlApplicationContext("applicationContext.xml"); 
        BookDao bookDao = (BookDao) ctx.getBean("bookDao"); 
        bookDao.save(); 
    } 
}

集合注入都是在bookDaobean标签中使用进行注入:

1.注入数组类型数据
<property name="array"> 
    <array> 
        <value>100</value> 
        <value>200</value> 
        <value>300</value> 
    </array> 
</property>

2.注入List类型数据
<property name="list"> 
    <list>
        <value>itcast</value> 
        <value>itheima</value> 
        <value>boxuegu</value> 
        <value>chuanzhihui</value> 
    </list> 
</property>

3.注入Set类型数据
<property name="set"> 
    <set>
        <value>itcast</value> 
        <value>itheima</value> 
        <value>boxuegu</value> 
        <value>boxuegu</value> 
    </set> 
</property>

4.注入Map类型数据
<property name="map"> 
    <map>
        <entry key="country" value="china"/> 
        <entry key="province" value="henan"/> 
        <entry key="city" value="kaifeng"/> 
    </map> 
</property>

5.注入Properties类型数据
<property name="properties"> 
    <props> 
        <prop key="country">china</prop> 
        <prop key="province">henan</prop> 
        <prop key="city">kaifeng</prop> 
    </props> 
</property>

运行程序结果略

property标签表示setter方式注入,
构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签
List的底层也是通过数组实现的,所以<list>和<array>标签是可以混用
集合中要添加引用类型,只需要把<value>标签改成<ref>标签,这种方式用的比较少

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值