Spring入门案例

Spring入门案例代码

1.创建Maven的java项目



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

<?xml version="1.0" encoding="UTF-8"?>


    4.0.0

    com.itheima
    spring_01_quickstart
    1.0-SNAPSHOT

    
        
            org.springframework
            spring-context
            5.2.10.RELEASE
        
        
            junit
            junit
            4.12
            test
        
    

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

package com.itheima.dao;

public interface BookDao {
    public void save();

}

package com.itheima.dao.impl;

import com.itheima.dao.BookDao;

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

package com.itheima.service;

public interface BookService {
    public void save();
}

package com.itheima.service.impl;

import com.itheima.dao.BookDao;
import com.itheima.dao.impl.BookDaoImpl;
import com.itheima.service.BookService;

public class BookServiceImpl implements BookService {
        //5.删除业务层中使用new的方式创建的dao对象
        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配置文件,并完成bean的配置

applicationContext.xmll

<?xml version="1.0" encoding="UTF-8"?>

    

    
    
    

    
        
        
        
    

注意:配置中的两个bookDao的含义是不一样的

name="bookDao"中bookDao的作用是让Spring的IOC容器在获取到名称后,将首字母大写,前 面加set找对应的setBookDao()方法进行对象注入

ref="bookDao"中bookDao的作用是让Spring能在IOC容器中找到id为bookDao的Bean对象给

bookService进行注入

综上所述,对应关系如下:



5.从容器中获取对象进行方法调用

package com.itheima;

import com.itheima.dao.BookDao;
import com.itheima.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

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基础配置

bean基础配置(id与class)


bean的name属性

name为bean指定别名,别名可以有多个,使用逗号,空格、分号隔开。



根据名称容器中获取bean对象

public class AppForName {

public static void main(String[] args) {

ApplicationContext ctx = new

ClassPathXmlApplicationContext("applicationContext.xml");

//此处根据bean标签的id属性和name属性的任意一个值来获取bean对象

BookService bookService = (BookService) ctx.getBean("service4");

bookService.save();

}

}

bean作用范围scope配置



bean为单例的意思是在Spring的IOC容器中只会有该类的一个对象

bean对象只有一个就避免了对象的频繁创建与销毁,达到了bean对象的复用,性能高

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

如果对象是有状态对象,即该对象有成员变量可以用来存储数据的, 因为所有请求线程共用一个bean对象,所以会存在线程安全问题。

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

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

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

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

bean实例化方法

构造方法实例化


    

Spring底层使用的是类的无参构造方法。关于Spring的构造方法实例化就已经学习完了,因为每一个类默认都会提供一个无参构造函 数,所以其实真正在使用这种方式的时候,我们什么也不需要做。这也是我们以后比较常用的一种方式。

静态工厂实例化


    


看到这,可能有人会问了,你这种方式在工厂类中不也是直接new对象的,和我自己直接new没什么太 大的区别,而且静态工厂的方式反而更复杂,这种方式的意义是什么?

主要的原因是:

在工厂的静态方法中,我们除了new对象还可以做其他的一些业务操作,这些操作必不可少,如:

public class OrderDaoFactory {

public static OrderDao getOrderDao(){

System.out.println("factory setup....");//模拟必要的业务操作

return new OrderDaoImpl();

}

}


之前new对象的方式就无法添加其他的业务内容。

实例工厂与FactoryBean

接下来继续来研究Spring的第三种bean的创建方式实例工厂实例化:

环境准备

(1)准备一个UserDao和UserDaoImpl类

public interface UserDao {

public void save();

}

public class UserDaoImpl implements UserDao {

public void save() {

System.out.println("user dao save ...");

}

}

(2)创建一个工厂类OrderDaoFactory并提供一个普通方法,注意此处和静态工厂的工厂类不一样的 地方是方法不是静态方法

public class UserDaoFactory {

public UserDao getUserDao(){

return new UserDaoImpl();

}

}

(3)编写AppForInstanceUser运行类,在类中通过工厂获取对象

// //创建实例工厂对象

UserDaoFactory userDaoFactory = new UserDaoFactory();

// //通过实例工厂对象创建对象

UserDao userDao = userDaoFactory.getUserDao();

userDao.save();

实例工厂实例化

具体实现步骤为:

(1)在spring的配置文件中添加以下内容:

="userFactory" class="com.itheima.factory.UserDaoFactory"/>

="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

实例化工厂运行的顺序是:

创建实例化工厂对象,对应的是第一行配置

调用对象中的方法来创建bean,对应的是第二行配置

factory-bean:工厂的实例对象

factory-method:工厂对象中的具体创建对象的方法名,对应关系如下:


factory-mehod:具体工厂类中创建对象的方法名

(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();
   }
}

实例工厂实例化的方式就已经介绍完了,配置的过程还是比较复杂,所以Spring为了简化这种配置方 式就提供了一种叫FactoryBean的方式来简化开发。

FactoryBean的使用

具体的使用步骤为:

(1)创建一个UserDaoFactoryBean的类,实现FactoryBean接口,重写接口的方法

public class UserDaoFactoryBean implements FactoryBean {
    //代替原始实例工厂中创建对象的方法

            public UserDao getObject() throws Exception {
        return new UserDaoImpl();
   }
    //返回所创建类的Class对象

            public Class<?> getObjectType() {
        return UserDao.class;
   }
}

(2)在Spring的配置文件中进行配置

(3)AppForInstanceUser运行类不用做任何修改,直接运行

查看源码会发现,FactoryBean接口其实会有三个方法,分别是:

T getObject() throws Exception;


Class<?> getObjectType();


default boolean isSingleton() {
    return true;
}

方法一:getObject(),被重写后,在方法中进行对象的创建并返回

方法二:getObjectType(),被重写后,主要返回的是被创建类的Class对象

方法三:没有被重写,因为它已经给了默认值,从方法名中可以看出其作用是设置对象是否为单例,默 认true.

那如果想改成单例具体如何实现?

只需要将isSingleton()方法进行重写,修改返回为false,即可

//FactoryBean创建对象

public class UserDaoFactoryBean implements FactoryBean {
    //代替原始实例工厂中创建对象的方法

            public UserDao getObject() throws Exception {
        return new UserDaoImpl();
   }

    public Class<?> getObjectType() {

        return UserDao.class;
   }
 
    public boolean isSingleton() {
        return false;
   }
}

但是一般情况下我们都会采用单例,也就是采用默认即可。 所以isSingleton()方法一般不需要进行重写。

bean的生命周期

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

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

bean生命周期是什么? bean对象从创建到销毁的整体过程。

bean生命周期控制是什么?在bean创建后到销毁前做一些事情。

生命周期设置

添加生命周期的控制方法,具体的控制有两个阶段:

bean创建之后,想要添加内容,比如用来初始化需要用到资源

bean销毁之前,想要添加内容,比如用来释放用到的资源

步骤1:添加初始化和销毁方法

针对这两个阶段,我们在BooDaoImpl类中分别添加两个方法,方法名任意

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...");
   }
}

步骤2:配置生命周期

在配置文件添加配置,如下:


步骤3:运行程序


从结果中可以看出,init方法执行了,但是destroy方法却未执行,这是为什么呢?

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

知道了出现问题的原因,具体该如何解决呢?

close关闭容器

   ClassPathXmlApplicationContext ctx = new 
   ClassPathXmlApplicationContext("applicationContext.xml");
ctx.close();

注册钩子关闭容器

ctx.registerShutdownHook();

注意:registerShutdownHook在ApplicationContext中也没有

两种方式介绍完后,close和registerShutdownHook选哪个?

相同点:这两种都能用来关闭容器

不同点:close()是在调用的时候关闭,registerShutdownHook()是在JVM退出前调用关闭。 分析上面的实现过程,会发现添加初始化和销毁方法,即需要编码也需要配置,实现起来步骤比较多 也比较乱。

Spring提供了两个接口来完成生命周期的控制,好处是可以不用再进行配置init-method和

destroy-method

接下来在BookServiceImpl完成这两个接口的使用:

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


public class BookServiceImpl implements BookService, InitializingBean,

        DisposableBean {
    private BookDao bookDao;
    public void setBookDao(BookDao bookDao) {
        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");
   }
}

那第二种方式的实现,我们也介绍完了。

小细节

DI依赖注入

setter注入

  1. 注入引用类型对象
public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
   }
}

配置中使用property标签ref属性注入引用类型对象








2.注入简单数据类型

步骤1:声明属性并提供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:配置文件中进行注入配置

    <?xml version="1.0" encoding="UTF-8"?>




           

               

            

           

           

           

               

               

           


value:后面跟的是简单数据类型,对于参数类型,Spring在注入的时候会自动转换。

对于setter注入方式的基本使用就已经介绍完了, 对于

引用数据类型使用的是

对于简单数据类型使用的是

构造器注入

  1. 构造器注入引用数据类型

步骤1:提供构造方法

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

步骤2:配置文件中进行配置构造方式注入

在applicationContext.xml中配置

    <?xml version="1.0" encoding="UTF-8"?>




           

           

               

           

说明:

标签中

构造器注入多个引用数据类型

步骤1:提供多个属性的构造函数

步骤2:配置文件中配置多参数注入

构造器注入多个简单数据类型

步骤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:配置完成多个属性构造器注入

    <?xml version="1.0" encoding="UTF-8"?>





               

               

           

           

           

               

               

           

方式一:删除name属性,添加type属性,按照类型注入



           

           

方式二:删除type属性,添加index属性,按照索引下标注入,下标从0开始



           

           

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

  1. 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现 强制依赖指对象在创建的过程中必须要注入指定的参数
  2. 可选依赖使用setter注入进行,灵活性强 可选依赖指对象在创建过程中注入的参数可有可无
  3. Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相 对严谨
  4. 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选 依赖的注入
  5. 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注 入
  6. 自己开发的模块推荐使用setter注入

依赖自动装配

自动装配方式有哪些?

自动装配只需要修改applicationContext.xml配置文件即可:

(1)将标签删除

(2)在标签中添加autowire属性

    <?xml version="1.0" encoding="UTF-8"?>




           

           

           




注意事项:

需要注入属性的类中对应属性的setter方法不能省略 被注入的对象必须要被Spring的IOC容器管理 按照类型在Spring的IOC容器中如果找到多个对象,会报NoUniqueBeanDefinitionException

一个类型在IOC中有多个对象,还想要注入成功,这个时候就需要按照名称注入,配置方式为:

    <?xml version="1.0" encoding="UTF-8"?>




           

           

           




最后对于依赖注入,需要注意一些其他的配置特征:

1. 自动装配用于引用类型依赖注入,不能对简单类型进行操作

2. 使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用

3. 使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推 荐使用

4. 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

集合注入

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

先来回顾下,常见的集合类型有哪些?

举例——

(1)项目中添加添加BookDao、BookDaoImpl类

   public interface BookDao {
           public void save();
        }


        public class BookDaoImpl implements BookDao {
           

        public class BookDaoImpl implements BookDao {

           private int[] array;

           private List list;

   private Set set;

       private Map 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

下面的所以配置方式,都是在bookDao的bean标签中使用进行注入


        <?xml version="1.0" encoding="UTF-8"?>




           

       
   
        

注入数组类型数据



   

           100

           200

           300

       

注入List类型数据



   

           itcast

           itheima

           boxuegu

           chuanzhihui

       

注入Set类型数据




   

           itcast

           itheima

           boxuegu

           boxuegu

       

注入Map类型数据



   

           

           

           

       

注入Properties类型数据




   

           china

           henan

           kaifeng

       

说明:

标签
展开阅读全文

页面更新:2024-03-16

标签:容器   数据类型   实例   属性   入门   步骤   对象   工厂   案例   类型   方式   方法

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2008-2024 All Rights Reserved. Powered By bs178.com 闽ICP备11008920号-3
闽公网安备35020302034844号

Top