Spring5框架——IOC和DI

目录

Spring框架概述

1. Spring简介

2. Spring 特点

3. Spring的体系结构

4. Spring快速入门

 IOC容器

1. IOC底层原理

2. Bean管理

2.1 Bean标签基本配置

2.2 Bean实例化三种方式

2.3 bean作用域和生命周期

3. 依赖注入 DI

3.1 基于xml方式的注入

3.1 基于注解方式的注入

4. IOC接口(BeanFactory)


Spring框架概述

1. Spring简介

1、Spring是分层的Java SE/EE应用 full-stack(全栈)轻量开源框架,以IOCAOP为内核。

      轻量:依赖的jar包数量少,体量小  开源:免费提供源代码  全栈:各层都有对应的解决方案

2、Spring框架可以解决企业应用开发的复杂性。Spring提供了展现层 SpringMVC 和持久层 Spring JDBCTemplate 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE 企业应用开源框架。

3、Spring有两个核心部分:IOC和AOP

        (1)IOC(Inversion of Control):控制反转,把创建对象过程交给 Spring 进行管理

        (2)Aop(Aspect Orient Programming):面向切面编程,不修改源代码进行功能增强

2. Spring 特点

(1)方便解耦,简化开发

        通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。

(2)Aop 编程支持

        通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付

(3)方便程序测试

        可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。

(4)方便和其他框架进行整合

        Spring对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的支持。

(5)方便进行事务操作

        在Spring中,我们可以从单调烦闷的事务管理代码中(编程式)解脱出来,通过声明式方式灵活地进行事务的管理

(6)降低 API 开发难度

        Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,通过Spring的简易封装,这些Java EE API的使用难度大为降低

(7)Java 源码是经典学习范例

Spring的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对Java 设计模式灵活运用以及对 Java技术的高深造诣。它的源代码无意是 Java 技术的最佳实践的范例。

3. Spring的体系结构

Spring5框架——IOC和DI_第1张图片

4. Spring快速入门

4.1 Spring程序开发步骤

Spring5框架——IOC和DI_第2张图片

① 导入 Spring 开发的基本包坐标
② 编写 Dao 接口和实现类
③ 创建 Spring 核心配置文件
④ 在 Spring 配置文件中配置 UserDaoImpl
⑤ 使用 Spring 提供的 API 获得 Bean 实例 

4.2 导入Spring开发的基本包坐标

使用maven:


    5.0.5.RELEASE


    
    
        org.springframework
        spring-context
        ${spring.version}
    

 不使用maven的情况(使用maven的可跳过此部分):

下载Spring5

         SPRING官方网站改版后,建议都是通过 Maven和Gradle下载,对不使用Maven和Gradle开发项目的,载就非常麻烦,下给出Spring Framework jar官方直接下载路径:访问下载地址https://repo.spring.io/release/org/springframework/spring,下载最新版

Spring5框架——IOC和DI_第3张图片

                对下载完成的spring-5.2.6.RELEASE-dist压缩文件解压

Spring5框架——IOC和DI_第4张图片

          2.打开idea,创建普通java工程

                file-new proiect

Spring5框架——IOC和DI_第5张图片

       3.导入spring5的相关jar包(4个spring基本核心jar包+commons-logging.jar(日志包))

Spring5框架——IOC和DI_第6张图片

4.3 编写Dao接口和实现类

public interface UserDao {
    public void save();
}

public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("UserDao save method running....");
    }
}

4.4 创建Spring核心配置文件

在类路径下(resources)创建applicationContext.xml配置文件

Spring5框架——IOC和DI_第7张图片

 idea会自动生成

4.5 在Spring配置文件中配置UserDaoImpl

Spring5框架——IOC和DI_第8张图片

          bean标签,class类路径,id为给对象的别名         

4.6 使用Spring的API获得Bean实例

@Test
public void testAdd() {
     //1 加载 spring 配置文件
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     //2 获取配置创建的对象
     UserDao userDao = (UserDao)context.getBean("userDao");
     userDao.save();
}

总结:Spring的开发步骤 

① 导入坐标(配置pom)
② 创建Bean的类
③ 创建applicationContext.xml
④ 在配置文件中配置bean
⑤ 创建ApplicationContext对象getBean

 IOC容器

1. IOC底层原理

1、什么是 IOC
(1)控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理
(2)使用 IOC 目的:降低耦合度
(3)入门案例就是 IOC 实现

2、IOC 底层原理
(1)xml 解析、工厂模式、反射
原始方式,在一个类中调用另一个类的方法,要先创建该类的对象,然后调用该对象方法。此方式耦合度高。

使用工厂模式,建工厂类,工厂类解析被代理类的xml文件,通过反射创建目标对象。

Spring5框架——IOC和DI_第9张图片

 xml解析得到Class属性值。反射创建对象。降低了耦合,要改只需要改配置中的属性。  

2. Bean管理

什么是 Bean 管理
         Bean管理指的是两个操作
        (1)Spring 创建对象(实例化)
        (2)Spirng 注入属性(初始化)
2、Bean 管理操作有两种方式
        (1)基于 xml 配置文件方式实现
        (2)基于注解方式实现

2.1 Bean标签基本配置

用于配置对象交由Spring 来创建。

默认情况下它调用的是类中的无参构造函数,如果没有无参构造函数则不能创建成功。


基本属性:
id:Bean实例在Spring容器中的唯一标识
class:Bean的全限定名称

2.2 Bean实例化三种方式

无参构造方法实例化
工厂静态方法实例化
工厂实例方法实例化

1) 使用无参构造方法实例化

它会根据默认无参构造方法来创建类对象,如果bean中没有默认无参构造函数,将会创建失败

2) 工厂静态方法实例化

工厂的静态方法返回Bean实例

public class StaticFactoryBean {
    public static UserDao createUserDao(){
        return new UserDaoImpl();
    }
}

spring解析时发现factory-method,会找此全包名对应的内部属性的方法,返回对应的对象

3) 工厂实例方法实例化

工厂的非静态方法返回Bean实例

public class DynamicFactoryBean {
    public UserDao createUserDao(){
        return new UserDaoImpl();
    }
}

通过工厂对象中的方法获取对应的对象

2.3 bean作用域和生命周期

作用域

1、在 Spring 里面,设置创建 bean 实例是单实例还是多实例,这个叫bean的作用域
2、在 Spring 里面,默认情况下,bean 是单实例对象。单实例:只有一个对象,实例对象地址相同,多实例:每次都建新对象,实例对象地址不同

Spring5框架——IOC和DI_第10张图片

如何设置单实例还是多实例
(1)在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
(2)scope 属性值
        第一个值 默认值,singleton,表示是单实例对象
        第二个值 prototype,表示是多实例对象 

Spring5框架——IOC和DI_第11张图片

 (3)singleton 和 prototype 区别
         1)当scope的取值为singleton时Bean的实例化个数:1个
             Bean的实例化时机:当Spring核心文件被加载时,实例化配置的Bean实例
             Bean的生命周期:
             对象创建:当应用加载,创建容器时,对象就被创建了
             对象运行:只要容器在,对象一直活着
             对象销毁:当应用卸载,销毁容器时,对象就被销毁了
        2)当scope的取值为prototype
             Bean的实例化个数:多个
             Bean的实例化时机:当调用getBean()方法时实例化Bean
             对象创建:当使用对象时,创建新的对象实例
             对象运行:只要对象在使用中,就一直活着
             对象销毁:当对象长时间不用时,被 Java 的垃圾回收器回收了

生命周期
        从对象创建到对象销毁的过程

Bean生命周期配置
        init-method:指定类中的初始化方法名称
        destroy-method:指定类中销毁方法名称

演示 bean 生命周期

public class Orders {
 
 private String oname;
 //无参数构造
 public Orders() {
   System.out.println("第一步 执行无参数构造创建 bean 实例");
 }
 public void setOname(String oname) {
   this.oname = oname;
   System.out.println("第二步 调用 set 方法设置属性值");
 }
 //创建执行的初始化的方法
 public void initMethod() {
   System.out.println("第三步 执行初始化的方法");
 }
 //创建执行的销毁的方法
 public void destroyMethod() {
   System.out.println("第五步 执行销毁的方法");
 }
}

 
@Test
 public void testBean3() {
   ClassPathXmlApplicationContext context =
   new ClassPathXmlApplicationContext("bean4.xml");
   Orders orders = context.getBean("orders", Orders.class);
   System.out.println("第四步 获取创建 bean 实例对象");
   System.out.println(orders);
   //手动让 bean 实例销毁
   context.close();//执行此方法后才会调用destoryMethod
 }

Spring5框架——IOC和DI_第12张图片

其实bean的生命周期还有两步,过程叫bean的后置处理器

bean 的后置处理器,bean 生命周期有七步
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization 
(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
(6)bean 可以使用了(对象获取到了)
(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法) 

演示添加后置处理器效果

(1)创建类,实现接口BeanPostProcessor,创建后置处理器

public class MyBeanPost implements BeanPostProcessor {
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) 
throws BeansException {
     System.out.println("在初始化之前执行的方法");
     return bean;
 }
 @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) 
throws BeansException {
     System.out.println("在初始化之后执行的方法");
     return bean;
 }
}

Spring5框架——IOC和DI_第13张图片

3. 依赖注入 DI

依赖注入(Dependency Injection):依赖注入,就是注入属性。它是 Spring 框架核心IOC 的具体实现。

3.1 基于xml方式的注入

Bean的依赖注入方式

构造方法
set方法

第一种注入方式:使用 set 方法进行注入
(1)创建类,定义属性和对应的 set 方法(原始写法)

/**
* 演示使用 set 方法进行注入属性
*/
public class Book {
     //创建属性
     private String bname;
     private String bauthor;
     //创建属性对应的 set 方法
     public void setBname(String bname) {
         this.bname = bname;
     }
     public void setBauthor(String bauthor) {
         this.bauthor = bauthor;
     }
}

(2)在 spring 配置文件配置对象创建,配置属性注入 



     
     
     

p名称空间注入(了解)

 P命名空间注入本质也是set方法注入,使用 p 名称空间注入,可以简化基于 xml 配置方式

 第一步 在配置文件中添加p名称空间      

Spring5框架——IOC和DI_第14张图片

第二步 进行属性注入,在 bean 标签里面进行操作




 第二种注入方式:使用有参数构造进行注入

(1)创建类,定义属性,创建属性对应有参数构造方法

/**
* 使用有参数构造注入
*/
public class Orders {
     //属性
     private String oname;
     private String address;
     //有参数构造
     public Orders(String oname,String address) {
         this.oname = oname;
         this.address = address;
     }
}

       (2)在 spring 配置文件中进行配置        



     
     

xml注入其他类型属性

1、字面量(变量的值)
    null 值



     

    属性值包含特殊符号



    (不推荐)



     >]]>

2、注入属性-外部bean



     
     

ref=外部bean id 

3、注入属性-内部 bean



  
  
  
  
  
    
      
  
  

4、注入属性&级联赋值

第一种写法


   
   
   
   
   


   

在外部bean的基础上赋值

(2)第二种写法

Spring5框架——IOC和DI_第15张图片

在emp类中要给dept对象的属性赋值,需要先写获得对象的get方法



   
   
   
   
   
   

xml注入集合属性

1、注入数组类型属性
2、注入 List 集合类型属性
3、注入 Map 集合类型属性

(1)创建类,定义数组、list、map、set 类型属性,生成对应 set方法

public class Stu {
  //1 数组类型属性
  private String[] courses;
  //2 list 集合类型属性
  private List list;
  //3 map 集合类型属性
  private Map maps;
  //4 set 集合类型属性
  private Set sets;
  public void setSets(Set sets) {
     this.sets = sets;
  }
  public void setCourses(String[] courses) {
      this.courses = courses;
 }
  public void setList(List list) {
      this.list = list;
 }
  public void setMaps(Map maps) {
      this.maps = maps;
 }
}

(2)在 spring 配置文件进行配置



   
   
      
        java 课程
        数据库课程
      
   

 
   
     
       张三
       小三
     
   
 

 
   
       
       
   
   
 

   
     
       MySQL
       Redis
     
   

此处的集合只能用在当前的bean

4、在集合里面设置对象类型值

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

public class Stu {
    private String name;
    //学生选的课程
    private List coursesLists;
    public void setName(String name) {
        this.name = name;
    }
    public void setCoursesLists(List courses) {
        this.courses = courses;
    }
}

list集合类型注入对象



  


  



  
  
    
      
      
     
  

map集合类型注入对象




    
        
            
            
        
    

Properties的注入



    
        aaa
        bbb
        ccc
    

把集合注入部分提取出来

 有多个bean,可以引入这个公共的list

(1)在spring配置文件中引入名称空间util

Spring5框架——IOC和DI_第16张图片

(2)使用util 标签完成 list 集合注入提取 

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


   易筋经
   九阴真经
   九阳神功



   

引入其他配置文件(分模块开发)

实际开发中,Spring的配置内容非常多,这就导致Spring配置很繁杂且体积很大,所以,可以将部分配置拆解到其他 配置文件中,而在Spring主配置文件通过import标签进行加载

总结:

Spring5框架——IOC和DI_第17张图片spring的重点配置

3.1 基于注解方式的注入

1、什么是注解

Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置 文件可以简化配置,提高开发效率

Spring原始注解主要是替代的配置

Spring5框架——IOC和DI_第18张图片

(1)注解是代码特殊标记,格式:@注解名称(属性名称=属性值, 属性名称=属性值..)
(2)使用注解,注解作用在类上面,方法上面,属性上面
(3)使用注解目的:简化 xml 配置

2、Spring针对Bean管理中创建对象提供注解

(1)@Component
(2)@Service
(3)@Controller
(4)@Repository

* 上面四个注解功能是一样的,都可以用来创建 bean 实例。我们习惯把不同注解用在不同层中,让开发人员清晰当前组件的角色,实际混用都是可以的。

3、基于注解方式实现对象创建

开启组件扫描,扫描有注解的类,有注解则创建对象

在配置文件中引入context名称空间



    
    

com.atgui包下的所有类都能扫描

创建类,在类上面添加创建对象注解

//在注解里面 value 属性值可以省略不写,默认值是类名称,首字母小写
//UserService -- userService
@Component(value = "userService") //
public class UserService {
     public void add() {
         System.out.println("service add.......");
 }
}

开启组件扫描细节配置




  //只扫描Controller的注解





  //controller注解不扫描

4、基于注解方式实现属性注入

(1)@Autowired:根据属性类型进行自动装配
  示例:在service类中注入dao对象
  第一步 创建service 和 dao 对象(在 service 和 dao 类添加创建对象注解)
  第二步 在 service 注入 dao 对象(在 service 类添加 dao 类型属性,在属性上面使用注解)

@Service
public class UserService {
   //定义 dao 类型属性
   //不需要添加 set 方法
   //添加注入属性注解
   @Autowired 
   private UserDao userDao;
     public void add() {
       System.out.println("service add.......");
       userDao.add();
   }
}

@Repository
public class UserDaoImpl implements UserDao{
    @Override
    public void add() {
        System.out.println("userdao");
    }
}

 (2)@Qualifier:根据名称进行注入

   这个@Qualifier 注解的使用,和上面@Autowired 一起使用。(根据类型注入,一个接口(同类型)有多个实现类,要通过名称进一步确定)

@Service
public class UserService {
    @Autowired
    @Qualifier(value = "userimpl1")
    private UserDao userDao;
    public void add(){
        System.out.println("service Add....");
        userDao.add();
    }
}

@Repository(value = "userimpl1")
public class UserDaoImpl implements UserDao{
    @Override
    public void add() {
        System.out.println("userdao");
    }
}

(3)@Resource:可以根据类型注入,可以根据名称注入(是javax包中的,spring官方更推荐前两个)

//@Resource //根据类型进行注入
@Resource(name = "userDaoImpl1") //根据名称进行注入,此处参数名是name
private UserDao userDao;

(4)@Value:注入普通类型属性

@Value(value = "abc")
private String name;//abc注入到name中

5、完全注解开发

使用上面的注解还不能全部替代xml配置文件,还需要使用注解替代的配置如下:
    非自定义的Bean的配置: 
    加载properties文件的配置:
    组件扫描的配置:
    引入其他文件:

Spring5框架——IOC和DI_第19张图片

(1)创建配置类,替代 xml 配置文件

分核心配置文件:

@PropertySource("classpath:jdbc.properties")//加载类文件夹下的properties
public class DataSourceConfiguration {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")    
    private String url;
    @Value("${jdbc.username}")    
    private String username;
    @Value("${jdbc.password}")
    private String password;

    @Bean(name="dataSource")//返回值存储到Bean容器中
    public DataSource getDataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass(driver);
        dataSource.setJdbcUrl(url);
        dataSource.setUser(username);
        dataSource.setPassword(password);
        return dataSource;
}

主核心配置文件 

@Configuration //作为配置类,替代 xml 配置文件
@ComponentScan(basePackages = {"com.atguigu"})
@Import({DataSourceConfiguration.class})//导入分配置类
public class SpringConfig {
}

(2)编写测试类

@Test
public void testService2() {
   //加载配置类
   ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
   UserService userService = context.getBean("userService",UserService.class);
   System.out.println(userService);
   userService.add();
}

4. IOC接口(BeanFactory)

Spring5框架——IOC和DI_第20张图片

    1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂(读取配置文件,通过反射创建对象)
    2、Spring提供两种IOC容器实现方式:(两个接口)
     (1)BeanFactory:IOC容器的基本实现方式,是Spring内部的使用接口,不提供开发人员进行使用。 加载配置文件时候不会创建对象,获取(使用)对象时才去创建对象
     (2)ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用。代表应用上下文,可以通过其实例获得 Spring 容器中的 Bean 对象。 加载配置文件时就会把配置文件对象进行创建(更优,在服务器启动的时候就建好全部需要的对象)

 ApplicationContext的实现类
1)ClassPathXmlApplicationContext
它是从类的根路径下加载配置文件 推荐使用这种
2)FileSystemXmlApplicationContext
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
3)AnnotationConfigApplicationContext
当使用注解配置容器对象时,需要使用此类来创建 spring 容器。它用来读取注解。

getBean()方法使用

public Object getBean(String name) throws BeansException {//字符串参数
    assertBeanFactoryActive();
    return getBeanFactory().getBean(name);
}
public  T getBean(Class requiredType) throws BeansException {//字节文件参数
    assertBeanFactoryActive();
    return getBeanFactory().getBean(requiredType);
}

其中,当参数的数据类型是字符串时,表示根据Bean的id从容器中获得Bean实例,返回是Object,需要强转。

当参数的数据类型是Class类型时,表示根据类型从容器中匹配Bean实例,当容器中相同类型Bean有多个时,则此方法会报错。

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService1 = (UserService) 
applicationContext.getBean("userService");
UserService userService2 = applicationContext.getBean(UserService.class);

FactoryBean

1、Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
2、普通 bean:在配置文件中定义 bean 类型就是返回类型
3、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样
        第一步:创建类,让这个类作为工厂 bean,实现接口 FactoryBean
        第二步:实现接口里面的方法,在实现的方法中定义返回的 bean 类型

public class MyBean implements FactoryBean {//泛型类
 //定义返回 bean
 @Override
 public Course getObject() throws Exception {//定义类型和返回类型不一样的原因
   Course course = new Course();
   course.setCname("abc");
   return course;
 }
 @Override
 public Class getObjectType() {
   return null;
 }
 @Override
 public boolean isSingleton() {
   return false;
 }
}
@Test
public void test3() {
 ApplicationContext context =
 new ClassPathXmlApplicationContext("bean3.xml");
 Course course = context.getBean("myBean", Course.class);
 System.out.println(course);
}

定义类型是mybean,返回类型是course

xml自动装配

基于xml的自动装配实际开发中很少用,基本都用注解解决

1、什么是自动装配
(1)根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入
2、演示自动装配过程
(1)根据属性名称自动注入



 


(2)根据属性类型自动注入


 


此处由于类型相同(Dept)会报错

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