Spring5框架day01之IOC容器

一、入门案例

首先在IDEA中创建一个项目,导入所需的Spring基础jar包,包括beans、context、core、expression四个jar包和一个日志包,保证最基础的Spring功能

1.创建基本类

Spring的最基础使用便是降低类与类之间的耦合,那么就需要先创建一个基础类

package spring01day.work01.User;

public class User {
 
    public void response(){
        System.out.println("we have got your request...");
    }
}

2.创建xml文件

右键点击src,在最底下选择xml文件,选择spring进行创建。xml文件是使用spring方式连接类与类之间的最基本的方式,创建完成使用bean指令,填入两个参数

其中id是调用xml文件时要指定的值,这样能找到使用的是哪个bean指令。class是连接当前类的路径








3.使用main方法进行调用(获取)

package spring01day.work01.test;




import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring01day.work01.User.User;

public class test {

    public static void main(String[] args) {
        new test().test_();
    }
    public void test_(){
        //使用类ApplicationContext来读取xml文件内容
        //如果xml文件在src下使用ClassPathXmlApplicationContext
        //如果xml文件不在src下则使用FileSystemXmlApplicationContext
        ApplicationContext context = new ClassPathXmlApplicationContext("spring01.xml");
        //使用getBean方法得到user对象,其中String为xml文件中定义的id,Class为xml中class对应路径的类名
        User user = context.getBean("user", User.class);
        user.response();
        System.out.println(user);
    }
}

最后可以获得输出结果

Spring5框架day01之IOC容器_第1张图片

 二、IOC容器

1.IOC的底层原理

(1)IOC的使用目的

IOC为控制反转,它使用目的是为了降低类与类之间的耦合度,在此之前如果想在A类中调用B类中的方法,那使用的是在A类中new一个B类的对象并调用方法,如果对B类进行修改,那么大概率也要对A类进行修改,这种牵一发而动全身的方法不利于代码的维护,所以使用IOC进行连接能大大的降低耦合度,也叫做解耦操作。

(2)工厂模式

降低类与类之间耦合的一种模式,代码如下

import spring01day.work01.User.User;

public class UserFactory {
    public static User getUser(){
        return new User();
    }
}

User对象与上示例相同,可直接通过UserFactory获取到User对象

不过这并非最优办法,要使解耦达到最优,就需要使用xml解析工厂模式类加载三者结合,即上示例所使用的IOC过程

(3)Spring提供IOC的两种实现接口

BeanFactory接口:一般用于Spring内部的使用,不提供给开发者使用,因为BeanFactory接口在解析过程中是不会创建对象的,只有在调用时才会创建对象,对于web项目,一般会在服务器启动时就将对象创建,这样会节省更多的时间。

        //如果xml文件在src下使用ClassPathXmlApplicationContext
        //如果xml文件不在src下则使用FileSystemXmlApplicationContext
        BeanFactory context = new ClassPathXmlApplicationContext("spring01.xml");
        //使用getBean方法得到user对象,其中String为xml文件中定义的id,Class为xml中class对应路径的类名
        User user = context.getBean("user", User.class);
        user.response();
        System.out.println(user);

ApplicationContext接口:BeanFactory接口的子接口,拥有更多更好用的功能,常由开发者使用的接口,原因是在解析过程中创建对象,对于web项目而言会节省用户访问的时间。

//使用类ApplicationContext来读取xml文件内容
//如果xml文件在src下使用ClassPathXmlApplicationContext
//如果xml文件不在src下则使用FileSystemXmlApplicationContext
ApplicationContext context = new ClassPathXmlApplicationContext("spring01.xml");
//使用getBean方法得到user对象,其中String为xml文件中定义的id,Class为xml中class对应路径的类名
User user = context.getBean("user", User.class);
user.response();
System.out.println(user);

其中ClassPathXmlApplicationContext和FileSystemXmlApplicationContext是实现ApplicationContext接口的类,它们能够根据文件路径获取并解析xml

2.Bean使用xml注入的方式

(1)创建类与属性注入

使用xml文件创建bean标签来注入类,再使用property标签注入属性,其中name为属性名,value为要注入的值


    
        
        
        
        
    

再通过ApplicationContext获取的对象即可得到注入的属性

如果是private权限的属性,那必须要生成set方法才能进行属性注入,否则将抛出异常

(2)有参构造器注入属性

使用constructor-arg标签注入属性,它也有两个值,一个为属性名的name,一个为注入值得value


    
        
        
        
        
    

也可以使用索引值注入,索引值从0开始,表示有参构造器中的第一个属性


    
        
        
        
        
    

(3)p标签的使用(简化xml代码)

首先配置p标签在文件中

 再通过bean使用p标签,即可简化代码


    

(4)注入空值和特殊符号

注入空值,在property或者constructor-arg中去掉value使用标签


            
            
        

注入特殊符号,一种是使用各个符号对应的转义符号,类似小于号是<,另一种方式就是要使用方式注入,将特殊符号放入其中即可获取


        
        
        
        
            
            
        
        
        
    

(5)注入外部bean(即将一个对象作为属性注入到需要调用的类中)

第一步:创建两个类,其中一个为Dao,一个为Service,把Dao作为Service的一个属性

package spring01day.work04.dao;

public class UserDaoImpl implements UserDao{
    @Override
    public void add() {
        System.out.println("data has been adding...");
    }
}
package spring01day.work04.service;

import spring01day.work04.dao.UserDao;

public class UserService {
    //要使用IOC方法注入UserDao对象,先创建一个UserDao属性,并设置set方法
    private UserDao dao;

    public void setDao(UserDao dao) {
        this.dao = dao;
    }

    public void impl(){
        dao.add();
    }
}

需要实现Dao的set方法

第二步:配置xml文件,使用ref标签将其注入




    
    
    

    
    
        
        

    

最后:使用测试类进行调用,可以发现Dao中的add方法被成功调用

package spring01day.work04.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring01day.work04.service.UserService;

public class test {
    public static void main(String[] args) {
        new test().test_();
    }
    public void test_(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring01day/work04/spring04.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.impl();
    }
}

Spring5框架day01之IOC容器_第2张图片

 (6)注入内部bean和级联赋值

内部bean注入:

第一步与第三步和外部注入相同,唯一不同的是xml文件中的表述方法


    
        
        
            
        
    

把property中的ref替换成bean标签,表示创建UserDaoImpl对象即可实现与外部注入相同的效果

级联赋值:

指的是在使用外部bean注入与内部bean注入时,使用bean标签的同时在其中给属性赋上初始值

(7)注入集合类型属性(基本注入)

首先创建一个学生类,其中放入数组、集合属性以及set方法

package spring01day.work05.Stu;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

//创建一个学生类,里面包含四种属性,为数组、集合属性
public class Student {
    private String[] courses;
    private List lists;
    private Map maps;
    private Set sets;

    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public void setLists(List lists) {
        this.lists = lists;
    }

    public void setMaps(Map maps) {
        this.maps = maps;
    }

    public void setSets(Set sets) {
        this.sets = sets;
    }

    public String get(){
        return Arrays.toString(courses) + "\t" + lists + "\t" + maps + "\t" + sets;
    }
}

其次配置xml文件,完成对数组、集合的注入。数组与集合都有其对应的标签来实现多个数据的存储。




    
    
        
        
            
                语文
                数学
            
        
        
            
            
                小明
                王子明
            
        
        
            
            
                
                
            
        
        
            
            
                c
                m
            
        
    

(8)注入集合类型属性(对象注入与提取)

对象注入:

修改Stu类,并添加一个Course类

package spring01day.work06.Stu;

import java.util.List;

//创建一个学生类,里面包含四种属性,为数组、集合属性
public class Student {
    private List lists;

    public void setLists(List lists) {
        this.lists = lists;
    }

    @Override
    public String toString() {
        return lists + "";
    }
}
package spring01day.work06.Stu;

public class Course {
    private String name;

    public void setName(String name) {
        this.name = name;
    }
}

通过xml的配置获取




    
    
        
            
                
                
            
        
    
    
    
        
    
    
        
    

提取:使用公共集合类来简化创建对象时的初始化过程

先创建一个people类

package spring01day.work06.Stu;

import java.util.List;

public class people {
    private List list;

    public void setList(List list) {
        this.list = list;
    }
}

在xml文件中进行配置,要使用util标签在beans里进行修改,与p标签修改方式相同





    
    
        石敢当
        水不敢当
    

    
    
        
    

需要的时候调用公共集合类即可简化创建对象的过程

(9)工厂bean

使用工厂bean接口可以返回任意类型而非原先的固定类型

package spring01day.work07.factory;

import org.springframework.beans.factory.FactoryBean;
import spring01day.work06.Stu.Course;

//实现工厂bean以获取不同的返回类型,这样在test类中加载的类就变成了Course类
public class factoryBean implements FactoryBean {
    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setName("abc");
        return course;
    }

    @Override
    public Class getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}

实现FactoryBean接口的方法,在getObject中修改返回类型,即可在测试端接收到所修改的返回类型,xml代码如下:

package spring01day.work07.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring01day.work06.Stu.Course;


public class test {
    public static void main(String[] args) {
        new test().test_();
    }
    public void test_(){
        ApplicationContext context = new ClassPathXmlApplicationContext("spring01day/work07/spring07.xml");
        Course course = context.getBean("factory", Course.class);
        System.out.println(course);
    }
}

(10)bean的作用域

bean作用域的含义是bean标签创建的对象是单实例还是多实例,单实例指只创造一个对象,多实例指会创造多个对象,修改办法为使用scope标签,默认为singleton,即单实例对象,如若修改为多实例对象就将scope修改为prototype,xml文件如下


    
    
    

(11)bean的生命周期

bean生命周期有七步,其中两步需要实现BeanPostProcessor接口,分别为初始化之前执行的方法和初始化之后执行的方法,七步总体为:

(1)通过构造器创建 bean 实例(无参数构造)

(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)

(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization

(4)调用 bean 的初始化的方法(需要在xml中使用init-method进行配置初始化的方法)

(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization

(6)bean 可以使用了(对象获取到了)

(7)当容器关闭时候,调用 bean 的销毁的方法(需要在xml中使用destory-method进行配置销毁的方法)

(12)xml自动装配

在xml文件中注入属性初始值时有一种自动装配加外部注入的方式,可以省去写property标签的过程,具体需使用autowire标签来实现

autowire标签有两种自动装配方式,一种是通过名称进行自动装配,即byName,还有一种是通过类型进行自动装配,即byType

创建一个UserService类,其中需要一个UserDao类型的属性

package spring01day.work08.service;

import spring01day.work08.dao.UserDao;

public class UserService {
    //要使用IOC方法注入UserDao对象,先创建一个UserDao属性,并设置set方法
    private UserDao dao;

    public void setDao(UserDao dao) {
        this.dao = dao;
    }

    public void impl(){
        dao.add();
    }
}

方式一:配置xml文件为自动装配的byName类型


    

    
    

方式二:配置xml文件为自动装配的byType类型


    

    
    

(13)外部属性文件

在注入属性不常变的情况下,可以使用外部属性文件来注入,首先创建pro文件

pro.url=jdbc:mysql:///user_db
pro.username=root
pro.password=hsp
pro.driverClassName=com.mysql.jdbc.Driver

 修改xmlns的标签,存入context标签,使用此标签可以引入外部属性文件




    
    

    
    
    
    
        
        
        
        
    

3.Bean使用注解的方式

(1)创建对象

(1)@Component

(2)@Service

(3)@Controller

(4)@Repository

(5)@Bean(用于外部jar包导入时创建对象)

四种注解,使用任意一种都可以,其本质没有区别,只是在不同环境使用不同注解好让程序员区分

在使用之前,需要在xml中设置context空间,方法与外部属性文件中的一致,并使用其中的扫描标签进行扫描,如果存在多个扫描路径,可以使用逗号隔开,或者使用更高一级目录,这样其下目录都会被扫描




    
    
    

    
    

再创建一个User类,使用注解方式创建对象,其中如果不写value则使用默认的类名首字母小写作为id值

package spring01day.work10.User;

import org.springframework.stereotype.Component;

//使用注解的方式获取对象
//@Component(value = "user")中的value可以不写,如果不写则系统会默认使用类名首字母小写的id值
@Component(value = "user")
public class User {
    public void add(){
        System.out.println("adding......");
    }
}

(2)组件扫描配置

配置组件扫描可以更好地扫描到路径下不需要被扫描或者只需要被扫描的类


    
        
    
    
    
        
    

(3)基于注解方式实现属性注入

首先创建一个UserDao接口,使用UserDaoImpl去实现该接口

package spring01day.work11.dao;

import org.springframework.stereotype.Component;

@Component
public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("data has been adding...");
    }
}

①@Autowired注解:根据属性类型进行自动装配

package spring01day.work11.Service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import spring01day.work11.dao.UserDao;

@Service
public class UserService {

    //使用@Autowired注解自动装配,此处的Autowired与xml标签中的不同,此处默认是byType去创建对象,如果要使用byName,
    // 则需要配合一起使用@Qualifier注解
    @Autowired
    private UserDao dao;

    public void setDao(UserDao dao) {
        this.dao = dao;
    }

    public void impl(){
        dao.add();
    }
}

②@Qualifie注解r:根据名称进行注入

使用时要与@Autowired注解一同使用,常用于被多个类实现的接口

package spring01day.work11.Service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import spring01day.work11.dao.UserDao;

@Service
public class UserService {

    //使用@Autowired注解自动装配,此处的Autowired与xml标签中的不同,此处默认是byType去创建对象,如果要使用byName,
    // 则需要配合一起使用@Qualifier注解
    @Autowired
    @Qualifier(value = "userDaoImpl")
    private UserDao dao;

    public void setDao(UserDao dao) {
        this.dao = dao;
    }

    public void impl(){
        dao.add();
    }
}

③@Resource:可以根据类型注入,可以根据名称注入

直接使用@Resource可以实现根据类型注入,与@Autowired功能相同,同时还可以使用@Resource(name = "")的方式进行名称注入,这样写相比使用@Autowired加@Qualifie更简便,不过,@Resource不属于spring官方制作,属于java的一个拓展包,所以一般更建议使用@Autowired与@Qualifie

④@Value:注入普通类型属性

@Value(value = "abc")
private String name;

用于注入普通类型属性,即String,int类等

(4)完全注解开发

指完全使用注解的方式进行开发,舍弃掉原先的xml文件,使用配置类代替

package spring01day.work11.config.SpringConfig;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

//这个注解表示是配置类
@Configuration
//这个注解表示扫描范围
@ComponentScan(value = "spring01day.work11")
public class SpringConfig {
}

这样在测试部分也需要修改

package spring01day.work11.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring01day.work11.Service.UserService;
import spring01day.work11.config.SpringConfig.SpringConfig;

public class test {
    public static void main(String[] args) {
        new test().test_();
    }
    public void test_(){
        //此时不再使用ClassPathXmlApplicationContext获取xml文件,而是使用AnnotationConfigApplicationContext(),括号中加载类
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.impl();
    }
}

即可实现完全注解开发

你可能感兴趣的:(spring,java)