Spring-bean

Spring

一、IoC

  • 概念:aoc,即“控制反转”,不是什么技术,而是一种设计思想。传统的程序设计中,对象 A 如果依赖于对象 B,那么对象 A 通常会在自己的代码中直接实例化对象 B,即对象 A 对对象 B 的创建和管理具有控制权。而在 IoC 模式下,对象 A 不再负责创建和管理对象 B,而是由一个外部的 IoC 容器来负责创建对象 B,并将其注入到对象 A 中,对象 A 只需要使用对象 B 即可,这就实现了控制的反转,即将对象的创建和依赖关系的管理控制权从对象本身反转到了外部容器。(在IoC容器中可以存放对象,以及保存对象之间的关系)

如下例子说明IoC存放对象的创建、对象之间的关系也可以存放在IoC容器里,实现代码解耦:

//获取IoC容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器里面获取bean
BookDao bookDao=(BookDao) ctx.getBean("bookDao");
bookDao.save();

BookService bookService=(BookService) ctx.getBean("bookService");
bookService.save();
	id表示获取的bean的名字,class表示bean代表的是哪一个类,scope表示造出的bean是否单例,即获取一个bean是否就得到一个对象,理解为用同一个bean就得到一个对象,这个称为单例;同一个bean也可以得到多个对象,这个称为非单例。默认是单例。
	<bean id="bookDao1" class="com.liu.dao.impl.BookDaoImpl" scope="pretotype"/>
    <bean id="bookService" class="com.liu.service.impl.BookServiceImpl">
<!--        配置dao与service之间的关系,bookService里面用到了bookdao的对象,所以在bookService里面添加与bookdao之间的关系,其实就是说明在service类里面的类属性bookDao就是id=bookDao1的bean的表示类-->
        <property name="bookDao" ref="bookDao1"/>	
    </bean>
  • bean是如何创建的?

    bean本质上就是对象,那么就是用实例化对象的方式来实现bean的实例化。

    方式一使用构造方法实现

    spring使用bean的时候调用的是无参的构造方法,创建一个对象是要调用构造方法,构造方法无论是public还是private都可以调用,能够调用到private其实是反射机制。

    方式二:使用静态工厂实现,了解即可

    public class BookDaoImpl implements BookDao {
        public void save(){
            System.out.println("book dao save...");
        }
    }
    --------------------------------------------------------------
    public interface BookDao {
        void save();
    }
    
    --------------------------------------------------------------
    public class BookDaoFactory {
       public static BookDao getBookDaoFactory(){
          return new BookDaoImpl();
       }
    }
    
    --------------测试类,通过静态工厂创建对象--------------------------
    public static void main(String[] args){
            BookDao bookDao1=new BookDaoFactory().getBookDao();
            bookDao1.save();
        }
    
    ----------------------在bean里面的定义-------------------------
    //解释factory-method是指使用工厂的哪个方法造对象
    <bean id="bookDaoFactory" class="com.liu.factory.BookDaoFactory" factory-method="getBookDaoFactory"/>
    

方式三:使用实例工厂实例化bean,了解

​ 创建实例工厂对象,再通过实例工厂对象创建对象。在bean里先将工厂bean拿到,然后再造一个bean,将工厂bean传到后面这个bean里面

方式四:方式三的优化,常用

  • bean的生命周期

    生命周期:从创建到销毁的完整过程

    配置bean的生命周期的方法

    <bean id="bookDao" class="com.liu.dao.impl.BookDaoImpl" init-method="init" destroy-method="destroy"/>
    
    1. 初始化对象

      调用 Bean 的初始化方法,例如init-method指定的方法或者实现InitializingBean接口的afterPropertiesSet方法。在这个阶段,Bean 可以进行一些初始化操作,如建立数据库连接、加载配置文件等。

    2. 使用bean

    3. 关闭/销毁容器

二、依赖注入

​ 一种设计模式,控制反转的一种具体的实现方式。将对象所依赖的其他对象的创建和管理工作交给外部容器来完成,对象只需要被动地接受这些依赖对象。不需要创建它们。

1.方式一:使用方法传递

1)普通方法(set方法)

其实就是前面前面所学的内容,一个类里面有另一个类作为属性,然后得到该属性

<bean id="bookService" class="com.liu.service.impl.BookServiceImpl">
    <!--        配置dao与service之间的关系,bookService里面用到了bookdao的对象,所以在bookService里面添加与bookdao之间的关系-->
    <property name="bookDao" ref="bookDao"/>
</bean>

2)构造方法(其实就是写个构造方法)

不同的是bean里面写的不一样

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

    }
    ------------------------bean的写法---------------------
    <bean id="bookDao" class="com.liu.dao.impl.BookDaoImpl" />

    <bean id="bookService" class="com.liu.service.impl.BookServiceImpl">
        <constructor-arg name="bookDao" ref="bookDao"/> //constructor-arg表示使用构造方法
    </bean>
public class BookDaoImpl implements BookDao {

    private int num;
    private String a;

    public BookDaoImpl(int num, String a) {
        this.num = num;
        this.a = a;
    }

    public void save() {
        System.out.println("构造方式" + num + "," + a);
    }
 }
    --------------------bean的写法----------------------
     <bean id="bookDao" class="com.liu.dao.impl.BookDaoImpl">
        <constructor-arg name="num" value="1212"/>
        <constructor-arg name="a" value="sahu"/>
    </bean>

想法:“”表示使用构造方法注入,name表示属性,即构造方法传入的参数,然后赋值。ref表示关联的是哪个类,其实就是另一个类作为该类的一个属性,解释关联的是哪一个类。然后value就表示的是给参数赋的值,该传入的参数是普通的参数,也就是注入的值。

  • ​ 注意:强制注入使用构造器注入,可选依赖使用setter注入,有必要也可以使用两种注入方式

三、依赖自动装配

  • ​ 自动装配的方式:需要set方法,自动装配其实就是在bean里加入一个"autowire",然后选择不同的装配类型

  • ​ 自动装配简化了前面所谓的方法传递,但感觉从效果上看和set注入或者构造方法差不多(使用引用类型注入时),因为自动装配也有要写set方法,而且只是在写法上简化了一点,就是把类似“”这样的换成了在bean里面写这样的“ autowire="byName" ”,可以说更简洁了。

    ​ 1)按类型(比较常用)

    <bean id="bookService" class="com.liu.service.impl.BookServiceImpl" autowire="byType"/>
    

    ​ 2)按名称:指的是类里面的属性名称,来找到bean的id为该类属性名称一致的bean,将该bean注入,bean可以是一个类,也可以是一个方法,还可以将bean之间的联系加到bean里,用ref表示。

    如下面解释按名称装配时,BookServiceImpl 有属性bookDao,在表示BookDaoImpl的bean里用到autowire来实现自动装配,选择的是按名称装配,意思则是按照表示该bean的类的属性名称bookDao来匹配找到bean的id与其一致的bean,这就是按名称的自动装配。

    <bean id="bookDao" class="com.liu.dao.impl.BookDaoImpl"/>
    <bean id="bookService" class="com.liu.service.impl.BookServiceImpl" autowire="byName">
       ----------------------------------------------
       public class BookServiceImpl implements BookService {
        private BookDao bookDao;
    
        public void setBookDao(BookDao bookDao) {
            this.bookDao = bookDao;
        }
     }  
    

    ​ 3)按构造方法(不推荐使用)

    ​ 4)不启用自动装配

    • 注意事项: (1)自动装配用于引用类型依赖注入,不能对简单类型进行操作。

      ​ (2)使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,就是不能有两个相同类型的bean,不然不知道使用哪个bean,尽管它们是一样的。(推荐使用)

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

      ​ (4)自动装配优先级低于setter注入和构造器注入,同时出现时自动装配会失效。

四、集合注入(不常用)

​ 在bean里面添加元素,然后有不同的元素标签,来实现类里面的集合注入,其实和上面差不多的使用方法,用法大概是以下如此。

 <bean id="bookDao" class="com.liu.dao.impl.BookDaoImpl">
 	<property name="list">
 		<list>
 			<value>lili<value/>
 			<value>lala<value/>
 			<value>lclc<value/>
 		</list>
    </property/>
</bean>

五、数据源对象管理(就是第三方的bean),第三方资源配置管理

其实和上面的使用方法差不多,通俗来讲就是,哪个对象交给我管理,然后我给你提供哪些对应的属性,使用什么就使用什么,使用方法和上面学的差不多。

<!--    使用第三方数据的格式-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
    ------------------测试代码-----------------
    //和上面大差不差
     public void Test(){
        ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource dataSource =(DataSource) ctx.getBean("dataSource");
        System.out.println(dataSource);
    }

六、加载properties文件

配置写在配置文件中不合适,应该单独抽出来,例如一些连接数据库的配置信息将其单独抽取出来,写在properties文件里,接下来说明如何使用spring来加载properties里的信息。

​ 1)开启全新的空间:在头部加入如下信息。表示开启了一个xmlns命名空间,名字叫做context。大部分是这样开启。

xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">

​ 2)使用context空间加载properties文件:添加如下配置,location表示配置文件的位置

class="com.alibaba.druid.pool.DruidDataSource"表示引入的外部资源类,要先在pom.xml文件里引入该类的库信息

    <context:property-placeholder location="jdbc.properties"/>
<!--    使用属性占位符${}读取properties文件中的属性-->
    <bean class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.Driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

------------jdbc.properties文件里的配置信息-----------
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db
jdbc.username=root
jcbd.password=root

后期这个bean可以用注解行驶代替,使得开发更简洁。

posted @ 2025-04-19 00:40  里莉  阅读(10)  评论(0)    收藏  举报