Administrator
发布于 2022-09-27 / 57 阅读
0
0

Spring实验

实验2:根据bean的类型从IOC容器中获取bean的实例【★】

web.xml

 <bean id="person01" class="com.lly.beans.Person">
        <!--   property标签调用getter/setter方法为person对象属性赋值
               name指定属性名
               value指定属性值
                -->
        <property name="lastName" value="张三"></property>
        <property name="age" value="20"></property>
        <property name="email" value="person01@gmail.com"></property>
        <property name="gender" value="male"></property>
    </bean>

    <bean name="person02" class="com.lly.beans.Person">
        <property name="lastName" value="李四"></property>
    </bean>

Test

//通过类获取,如果有多个相同类型的组件,会报以下错误
//org.springframework.beans.factory.NoUniqueBeanDefinitionException:
No qualifying bean of type 'com.lly.beans.Person' available: 
expected single matching bean but found 2: person01,person02

  Person person = ioc.getBean(Person.class);
        System.out.println(person);
        
        //指定组件的id进行获取
        Person bean = ioc.getBean("person01", Person.class);
       System.out.println(bean);

实验3:通过构造器为bean的属性赋值

web.xml

    constructor-arg 标签属性介绍
    name值不指定的话,那么value的值要严格按照构造器的顺序写
    
    <constructor-arg value="wangwu"></constructor-arg>
        <constructor-arg  value="20"></constructor-arg>
        <constructor-arg  value="person01@gmail.com"></constructor-arg>
        <constructor-arg  value="male"></constructor-arg>
        
    index属性:指定对应参数的索引下标,从0开始
    value属性:设置参数的值
    type属性:指定该为 什么类型的参数,重载的情况下赋值可能造成混乱,
    可以显示指定改数值赋值给那种类型的参数
    <bean name="person03" class="com.lly.beans.Person">
		<!--    调用构造器进行属性赋值-->
        <constructor-arg name="lastName" value="wangwu"></constructor-arg>
        <constructor-arg name="age" value="20"></constructor-arg>
        <constructor-arg name="email" value="person01@gmail.com"></constructor-arg>
        <constructor-arg name="gender" value="male"></constructor-arg>
    </bean>

通过p名称空间赋值

    <!--通过p名称空间为bean赋值:  导入p名称空间 -->
    <!--名称空间: 在xml中名称空间是用来防止标签重复-->
    <!--1)导入p名称空间 2)写带前缀的标签/属性 
        <book>
            <b:name>西游记</b:name>
            <price>19.99</price>
            <author>
                <a:name>吴承恩</a:name>
                <gender>男</gender>
            </author>
        </book>

        带前缀的标签:<c:forEach>、<jsp:forward>...
    -->

以下来自于https://achang.blog.csdn.net/article/details/110704472,一样的课程,一样的实验,懒得自己做了,copy阿昌的。
版权声明:本文为CSDN博主「阿昌喜欢吃黄桃」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_43284469/article/details/110704472

实验4:正确的为各种属性赋值

复杂类型在标签体里写内容,不是在value属性里写

实体类

public class Person {

    //基本类型直接使用property标签
    //<property name="lastName" value="真田幸村"></property> 自动进行类型转换
    private String lastName;
    private Integer age;
    private String gender;
    private String email;

    private Car car;
    private List<Book> books;
    private Map<String,Object> maps;
    private Properties properties;
    //....
 
    //省略get/set()、有参无参、toString
}

web.xml

1  <!--测试使用null值-->
    <bean class="com.achang.bean.Person" id="person01">
        <property name="lastName">
            <!--复杂赋值-->
            <null></null>
        </property>
    </bean>

System.out.println(person01);
//Person{lastName='null', age=null, gender='null', email='null', car=null, books=null, maps=null, properties=null}

2.外部引用,通过ref属性:引用↓
    <bean id="car01" class="com.achang.bean.Car">
        <property name="carName" value="大泵"></property>
        <property name="color" value="绿色"></property>
        <property name="price" value="3000"></property>
    </bean>
    <bean class="com.achang.bean.Person" id="person01">
        <property name="car" ref="car01"></property>
    </bean>

System.out.println(person01.getCar());//Car{carName='大泵', price=3000, color='绿色'}



3.引用内部bean↓ ,在property标签里面在嵌套一个bean标签

    <bean id="car01" class="com.achang.bean.Car">
        <property name="carName" value="大泵"></property>
        <property name="color" value="绿色"></property>
        <property name="price" value="3000"></property>
    </bean>

    <bean class="com.achang.bean.Person" id="person01">
        <property name="car">
            <bean class="com.achang.bean.Car">
                <property name="carName" value="自行车"></property>
            </bean>
        </property>
    </bean>

Car car = person01.getCar();
System.out.println(car);// Car{carName='自行车', price=null, color='null'}


集合类型赋值(List、Map、Properties)
1.List

    <bean id="book01" class="com.achang.bean.Book">
        <property name="bookName" value="三国演义"></property>
        <property name="author" value="罗贯中"></property>
    </bean>

    <bean class="com.achang.bean.Person" id="person02">
        <!--如何为List类型赋值-->
        <property name="books">
        <!--book = new ArrayList<Book>();-->
            <list>
            <!--list标签体中,添加每一个元素-->
                <!--引用内部元素-->
                <bean id="book02" class="com.achang.bean.Book" >
                    <property name="bookName" value="西游记"></property>
                </bean>
                <!--引用外部元素-->
                <ref bean="book01"></ref>
            </list>
        </property>
        
    </bean>


      Person person02 = ioc.getBean("person02", Person.class);
        List<Book> books = person02.getBooks();
 // [Book{bookName='西游记', author='null'}, Book{bookName='三国演义', author='罗贯中'}]
        System.out.println(books);
      
内部bean不能被获取,只能内部使用
报错:No bean named ‘book02’ available  
        Object book02 = ioc.getBean("book02");
        System.out.println(book02);//报错 No bean named 'book02' available
        
      
2.Map

    <bean class="com.achang.bean.Person" id="person02">
        <!--如何为Map类型赋值-->
        <!--Map<String,Object> maps-->
        <property name="maps">
            
            <!-- map = new LinkedHashMap<>(); -->
            <map>
            <!-- 一个entry标签等于一个键值对 -->
            <entry key="姓名" value="刘备"></entry>
            <entry key="编号" value="18"></entry>
            <!--引用外部元素-->
            <entry key="书1" value-ref="book01"></entry>
            <entry key="书2">
                <!--引用内部元素-->
                <bean class="com.achang.bean.Book">
                    <property name="bookName" value="转行成功手册"></property>
                </bean>
            </entry>
            <entry key="">
                <map></map>
            </entry>
            </map>
            
        </property>
        
    </bean>


3.properties
    <bean class="com.achang.bean.Person" id="person02">
        
        <!-- Properties properties -->
        <property name="properties">
            <!-- properties = new Properties();-->
            <props>
                <!--所有的K=V都String,值直接写在标签体中-->
                <prop key="password">00000</prop>
                <prop key="username">root</prop>
            </props>

        </property>
        
    </bean>


 System.out.println(person02.getProperties());
 
 4.util名称空间创建集合类型的bean
 省略了。。。

实验5:配置通过静态工厂方法创建的bean、实例工厂方法创建的bean、FactoryBean【★】

工厂模式:工厂帮我们创建对象,有一个专门帮我们创建对象的类,这个类就是工厂
静态工厂:工厂本身不用创建对象;通过静态方法调用,
实例工厂:工厂本身需要被创建

实例工厂
public class AirPlaneInstanceFactory {
    //new AirPlaneStaticFactory().getAirPlane()
    public  Airplane getAirPlane(String jzName){
        Airplane airplane = new Airplane();
        airplane.setJzName(jzName);
        airplane.setFdj("海星");
        airplane.setFjsName("zyc");
        airplane.setPersonNum(300);
        airplane.setYc("145.23m");
        return airplane;
    }
}

静态工厂
public class AirPlaneStaticFactory {
    //AirPlaneStaticFactory.getAirPlane()
    public static Airplane getAirPlane(String jzName){
        Airplane airplane = new Airplane();
        airplane.setJzName(jzName);
        airplane.setFdj("海星");
        airplane.setFjsName("zyc");
        airplane.setPersonNum(300);
        airplane.setYc("145.23m");
        return airplane;
    }
}

web.xml

      静态工厂(不需要创建工厂本身)
      factory-method属性:指定哪个方法是工厂方法
      class属性:指定静态工厂的全类名
      constructor-arg标签:为工厂方法传参

<bean id="airPlane01" class="com.achang.factory.AirPlaneStaticFactory"
      factory-method="getAirPlane">
    <!--可以为方法指定参数-->
    <constructor-arg value="刘烨"></constructor-arg>
</bean>

输出

Object bean = ioc.getBean("airPlane01");
//不需要创建工厂本身,容器创建完就已经创建完毕工厂本身。
System.out.println(bean);
//Airplane{fdj='海星', yc='145.23m', personNum=300, jzName='刘烨', fjsName='zyc'}


web.xml

    实例工厂(需要创建工厂本身)
    factory-method属性:指定这个实例工厂中哪个方法是工厂方法
    factory-bean属性:指定当前bean对象创建使用哪个工厂
    constructor-arg标签:可以为工厂方法传参

创建流程
一、先配置出实例工厂对象,相当于先new了一个工厂对象
<bean class="com.achang.factory.AirPlaneInstanceFactory" id="airPlaneInstanceFactory"></bean>

二、配置要创建的AirPlane使用哪个工厂创建
1、 factory-bean属性:指定当前bean对象创建使用哪个工厂
2、factory-method属性:指定这个实例工厂中哪个方法是工厂方法
3、constructor-arg标签:设置工厂方法的参数
<bean class="com.achang.bean.Airplane" id="airPlane02"
factory-bean="airPlaneInstanceFactory" factory-method="getAirPlane"
>
<constructor-arg value="李磊"></constructor-arg>
</bean>

输出

Object bean1 = ioc.getBean("airPlane02");
System.out.println(bean1);
//Airplane{fdj='海星', yc='145.23m', personNum=300, jzName='李磊', fjsName='zyc'}

FactoryBean★(是Spring规定的一个接口)

只要是这个接口的实现类,Spring都认为是一个工厂
且ioc容器启动时,无论是单多实例,都不会创建实例,在获取的时候才创建

/******
 * 实现了FactoryBean接口的类都是Spring可以认识的工厂类;
 * Spring会自动调用工厂方法创建实例
 *
 *
 @author 阿昌
 @create 2020-12-05 17:03
 *******
 */
public class MyFactoryBeanImpl implements FactoryBean<Book> {

    //getObject():工厂方法,Spring自动调用
    //返回创建的对象
    @Override
    public Book getObject() throws Exception {
        Book book = new Book();
        book.setBookName();
        return book;
    }


    //返回创建类型类型,Spring自动调用确认创建对象是什么类型
    @Override
    public Class<?> getObjectType() {
        return Book.class;
    }


    //isSingleton:是单例吗?
    //false:不是单例
    //true:是单例
    @Override
    public boolean isSingleton() {
        return false;
    }
    
}

web.xml

注册到容器中
<bean class="com.achang.factory.MyFactoryBeanImpl" id="factoryBean"></bean>

实验6:通过继承实现bean配置信息的重用

web.xml

parent属性:指定当前bean的配置信息继承于哪个,只是配置信息

<!--实验6:通过继承实现bean配置信息的重用-->
<bean id="person05" class="com.achang.bean.Person">
    <property name="lastName" value="周瑜"></property>
    <property name="age" value="18"></property>
    <property name="gender" value="男"></property>
    <property name="email" value="zhouyu@achang.com"></property>
</bean>

<!--parent属性:指定当前bean的配置信息继承于哪个,其他要变的就在下面改,不变的就用别人的-->
<bean id="person06" parent="person05">
    <property name="lastName" value="孙策"></property>
</bean>

输出

Object person06 = ioc.getBean("person06");
        System.out.println(person06);
//Person{lastName='孙策', age=18, gender='男', email='zhouyu@achang.com', 
car=null, books=null, maps=null, properties=null}

实验7:通过abstract属性创建一个模板bean

      如果某一个类只想被人继承怎么办?
<!--    abstract="true" 这个bean是抽象的,不能获取实例,只能被继承-->
    <bean id="person05" class="com.achang.bean.Person" abstract="true">
        <property name="lastName" value="周瑜"></property>
        <property name="age" value="18"></property>
        <property name="gender" value="男"></property>
        <property name="email" value="zhouyu@achang.com"></property>
    </bean>

    <!--parent属性:指定当前bean的配置信息继承于哪个-->
    <bean id="person06" parent="person05">
        <property name="lastName" value="孙策"></property>
    </bean>
    
    输出
    
    Object person05 = ioc.getBean("person05");
//报错: Error creating bean with name 'person05': Bean definition is abstract;只能获取person06
System.out.println(person05);


实验8:bean之间的依赖

所谓依赖:就是谁先创建谁后创建

dpends-on属性:使该bean对象依赖于某bean对象,从左到右是先后创建顺序
web.xml

<!--按照配置的顺序创建bean-->
    <bean class="com.achang.bean.Book" id="book" depends-on="car,person"></bean>
    <bean class="com.achang.bean.Person" id="person"></bean>
    <bean class="com.achang.bean.Car" id="car"></bean>

输出

@Test
public void test7(){
	//Car的无参构造器
	//Person的无参构造器
	//Book的无参构造器
}

实验9:测试bean的作用域,分别创建单实例和多实例的bean【★】

bean的作用域:bean是否单实例;默认,单实例

scope属性:设置单例模式、多例模式

singleton:单实例模式;默认
1)在容器启动完成之前,就已经创建好对象,并保存在容器中
2)任何时候获取都是获取之前创建好的那个对象

prototype:多实例模式;
1)在容器启动默认不会去创建多实例bean
2)获取时,才创建bean
3)每次获取都会创建一个新的实例,每次都会调用构造器创建

web.xml

<bean class="com.achang.bean.Car" id="car" scope="prototype"></bean>
<bean class="com.achang.bean.Book" id="book" scope="singleton"></bean>

实验10:创建带有生命周期方法的bean

生命周期: bean的创建到销毁;

ioc容器注册的bean:
1、单例bean,容器启动时创建好,容器关闭就销毁
2、多例bean,获取时才创建

  单例Bean的生命周期

  构造器—>初始化方法—>(容器关闭)销毁方法

  多例Bean的生命周期

  获取bean时(构造器创建对象)—>初始化方法—>(容器关闭)不会调用销毁方法

我们可以为bean自定义一些生命周期方法;Spring在创建或销毁时会自动调用
自定义初始化方法和销毁方法;The method must have no arguments, but may throw any exception.

web.xml

    destroy-method属性:销毁方法
    init-method属性:初始化方法
    
<bean class="com.achang.bean.Book" id="book" init-method="myInit"
				destroy-method="myDestory" scope="prototype"></bean>

实验11:测试bean的后置处理器

后置处理器:

(容器启动)构造器—>后置处理器before方法—>初始化方法—>后置处理器的after方法

无论bean是否有初始化方法;后置处理器都会工作,默认其有,还会继续工作
Object bean参数为: 将要初始化的bean
String beanName 参数为: 将要初始化bean的名字

1、编写后置处理器的实现类
2、讲后置处理器注册到配置文件中

MyBeanPostProcessor

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【"+beanName+"】bean将要调用初始化方法了...这个bean对象是: "+bean);

        //返回传入的bean
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("【"+beanName+"】bean初始化完了了...这个bean对象是: "+bean);

        return bean;
    }
}

web.xml

<!--实验11:测试bean的后置处理器:BeanPostProcessor
Spring有一个接口,后置处理器:可以在bean的初始化前后调用方法;
-->
<!--将自定义的后置处理器加入到容器中-->
<bean class="com.achang.bean.MyBeanPostProcessor" id="myBeanPostProcessor"></bean>
<bean class="com.achang.bean.Car" id="car"></bean>

实验12:引用外部属性文件【★】—Spring管理连接池

通过Spring单例与数据库连接池连接(这里使用的阿里巴巴德鲁伊数据库连接池)
web.xml

<!--实验12:引用外部属性文件【★】-->
<!--数据库连接池作为单例是最好的;一个项目就一个连接池,连接池里面管理很多连接。连接是直接从连接池里拿-->
<!--可以让Spring帮我们创建连接池对象,(管理连接池)-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="username" value="root"></property>
    <property name="password" value="00000"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/test"></property>
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
</bean>

输出

@Test
public void test2() throws SQLException {
    //1、从容器中拿到连接池
    //2、按照类型获取组件,可以获取到这个类型下的所有实现类
    DataSource bean = ioc.getBean(DataSource.class);

    System.out.println(bean.getConnection());//com.mysql.jdbc.JDBC4Connection@77e4c80f

}

通过properties文件读取

dbconfig.properties

jdbc_username=root
password=00000
url=jdbc:mysql://localhost:3306/test
driverClassName=com.mysql.jdbc.Driver

web.xml

<contex:properties id="dbProperties" location="dbconfig.properties"></contex:properties>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <!--username是Spring的key中的一个关键字;为了防止配置文件中与spring关键字冲突-->
    <property name="username" value="${jdbc_username}"></property>
    <property name="password" value="${password}"></property>
    <property name="url" value="${url}"></property>
    <property name="driverClassName" value="${driverClassName}"></property>
</bean>

实验13:基于XML的自动装配(自动赋值)

自动赋值(自动装配):仅限于对自定义类型的属性有效;自动的为属性赋值

autowire属性:

default/no===不自动装配

byName===以属性名(car)作为id去容器中找到这个组件,给他赋值;如果找不到就装配nul
car = ioc.getBean(“car”);

ByType===以属性的类型作为查找依据去容器中找到这个组件
1、如果容器中有多个这种类型的组件,会提示报错
2、没找到会装配null
car = ioc.getBean(Car.class);

constructor===按照构造器进行赋值
1、先按照有参构造器参数的类型装配;没有就装配null
2、如果类型有多个;参数的名作为id继续匹配;找到就装配,找不到就null
3、不会报错

  List books:容器可以把容器中的所有book封装list赋值给这个属性

web.xml

    <bean class="com.achang.bean.Car" id="car">
        <property name="carName" value="老坛"></property>
        <property name="price" value="6000"></property>
        <property name="color" value="紫色"></property>
    </bean>

    <!-- 为Person里面的自定义类型的属性赋值
        property:手动赋值
    -->
    <bean class="com.achang.bean.Person" id="person" autowire="constructor"></bean>

实验14:[SpEL测试I]

 简介
 Spring Expression Language,Spring表达式语言,简称SpEL。支持运行时查询并可以操作对象图。
 
 和JSP页面上的EL表达式、Struts2中用到的OGNL表达式一样,SpEL根据JavaBean风格的getXxx()、setXxx()方法定义的属性访问对象图,完全符合我们熟悉的操作习惯。

基本语法
 #{T(全类名).静态方法名(参数1,参数2)}

—在SpEL中使用字面量、
—引用其他bean、
—引用其他bean的某个属性值、
—调用非静态方法
—调用静态方法、
—使用运算符

web.xml

<bean id="person2" class="com.achang.bean.Person" >
<!--字面量:${};       #{}-->
    <property name="salary" value="#{1234*12}"></property>
<!-- 引用其他bean的某个属性值-->
    <property name="lastName" value="#{car.carName}"></property>
    <property name="car" value="#{car}"></property>
<!--调用静态方法:UUID.randomUUID().toString()
                #{T(全类名).静态方法名(参数1,参数2)}
            -->
    <property name="email" value="#{T(java.util.UUID).randomUUID().toString()}"></property>
<!--调用非静态方法; 对象.方法名
        -->
    <property name="gender" value="#{car.getCarName()}"></property>

</bean>

实验15:通过注解分别创建Dao、Service、Controller【★】

相对于以上的XML方式而言,通过注解的方式配置bean更加简洁和优雅,而且和MVC组件化开发的理念十分契合,是开发中常用的使用方式。

使用注解标识组件
①普通组件:@Component
标识一个受Spring IOC容器管理的组件;给不属于其他层的组件添加这个注解

②持久化层组件:@Respository
标识一个受Spring IOC容器管理的持久化dao层组件

③业务逻辑层组件:@Service
标识一个受Spring IOC容器管理的业务逻辑Service层组件;

④表述层控制器组件:@Controller
标识一个受Spring IOC容器管理的表述Servlet层控制器组件;

⑤组件命名规则

[1]默认情况:使用组件的为简单类名首字母小写后得到的字符串作为bean的id
[2]使用组件注解的value属性指定bean的id

组件的id。默认为_组件类名首字母小写
//开发一般不用这么做
@Controller("bookServlethh")或(value="bookServlethh")
public class BookServlet{}

使用注解将组件快速的加入到容器中需要几步:

1)给需要添加的组件上标四个注解的任何一个
2)告诉Spring自动扫描加了注解的组件;依赖context名称空间
3)一定要导入aop包,才支持加注解模式

组件的作用域—默认为单例模式,可通过@Scope修改作用域模式
@Scope(value = “prototype”)

      注意:事实上Spring并没有能力识别一个组件到底是不是它所标记的类型,
      即使将@Respository注解用在一个表述层控制器组件上面也不会产生任何错误,
      所以@Respository、@Service、@Controller这几个注解仅仅是为了
      让开发人员自己明确当前的组件扮演的角色。

扫描组件
context:component-scan标签:

自动组件扫描
base-package属性:
指定扫描的基础包;把基础包及下面所有包的所有加了注解的类,自动扫描进ioc容器中

web.xml

<context:component-scan base-package="com.xxxx"/>

实验16:使用context:include-filter指定扫描包时要包含的类—包含

只扫描进那些组件;默认都是全部扫描
一定要禁用掉默认的过滤规则才行:

use-default-filters属性=“false”

web.xml

<context:component-scan base-package="com.achang" use-default-filters="false">
    <!--指定只扫描那些组件-->
    <context:include-filter expression="org.springframework.stereotype.Service" type="annotation"/>
</context:component-scan>

实验17:使用context:exclude-filter指定扫描包时不包含的类—排除

web.xml

//扫描的时候可以排除不要的组件
<context:component-scan base-package="com.achang" use-default-filters="false">
   <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>

【type="annotation"】:指定排除某个注解。标注指定注解的组件不要扫描
      expression属性:指定注解类型的全类名
【type=assignable】:指定排除某个具体的类,按照类排除
      expression属性:指定类的全类名
type=aspectj:后来aspectj表达式
type=custom:自定义一个TypeFilter;自己写代码觉得排除规则,编写一个类实现TypeFilter类的match()方法
tyoe=regex:正则表达式

实验18:使用@Autowired注解实现根据类型实现自动装配【★】

web.xml

//先加入扫描组件
<context:component-scan base-package="com.achang"></context:component-scan>

实验19-22 【只总结原理和区别】

实验19:如果资源类型的bean不止一个,
默认根据@Autowired注解标记的成员变量名作为id查找bean,进行装配★

实验20:如果根据成员变量名作为id还是找不到bean,
可以使用@Qualifier注解明确指定目标bean的id★

实验21:在方法的形参位置使用@Qualifier注解

实验22:@Autowired注解的required属性指定某个属性允许不被设置

@Autowired原理【★】

<!--@Autowired原理
@Autowired
private BookService bookService;
    1、先按照类型去容器找到对应的组件; bookService = ioc.getBean("BookService.class");
        ①匹配成功;装配
        ②匹配失败;抛出异常报错
        ③匹配多个;
            按照变量名作为id继续匹配
                1)匹配成功;装配
                2)匹配失败;抛出异常报错
                    失败原因:Spring会使用id在容器中匹配
                    【可使用@Qualifier("xxxXxx")指定一个新id匹配】
                        1)匹配成功;装配
                        2)匹配失败;抛出异常报错

      发现AutoWired标注的自动装配的属性默认是一定装配上,任何情况下没匹配就是抛出异常报错
            找到就装配,找不到就拉倒
            @Autowired(required=false):默认为true,给为匹配上的赋值为null
	----------------------------------------------------------------------------------------
	先按照类型找,找到装配,找不到就按变量名做id找,找到装配,找不到抛异常
	可以用@Qualifier指定id去匹配;此注解可修饰参数

@Autowired和@Resource、@Inject的区别【★】

@Autowired、@Resource、@Inject都可以作为注入注解

@Autowired:最强大;Spring的注解
    ①扩展性差,依赖Spring容器框架

@Resource:j2ee;java的标准【jdk标准】
    ①扩展性强:切换成另一个容器框架,其还会可以使用

【@Inject:在EJB环境下使用()】

Spring单元测试

 1、导入:Spring单元测试包
 2、@ContextConfiguration(locations = ""),指定Spring的配置文件位置
 3、@RunWith(),指定用哪种驱动进行单元测试,默认junit
          @RunWith(SpringJUnit4ClassRunner.class)
          使用Spring的单元测试模块来执行@Test注解的测试方法;
          之前@Test由Junit执行
 好处:
     不需要ioc.getBean()获取组件;直接AutoWired组件,Spring自动装配

exp

@ContextConfiguration(locations = "classpath:applicationContext.xml");
@RunWith(SpringJUnit4ClassRunner.class)
public class IOCTest {
	@Test
	public void test3(){
		System.out.println(bookServlet);
	}
    
}

实验23:测试泛型依赖注入★

exp:

public abstract class BaseDao<T> {
    public abstract void save();
}

---------------------------------------------
@Repository
public class BookDao extends BaseDao<Book>{
    @Override
    public void save() {
        System.out.println("BookDao。。。保存图书");
    }

    
}
-------------------------------------------------
public class UserDao extends BaseDao<User> {
    @Override
    public void save() {
        System.out.println("UserDao。。。保存用户");
    }
    
}
----------------------------------------------
public class UserDao extends BaseDao<User> {
    @Override
    public void save() {
        System.out.println("UserDao。。。保存用户");
    }
    
}
-----------------------------------------------------
public class BaseService<T> {
    @Autowired
    BaseDao baseDao;

    public void save(){
        System.out.println("自动注入的dao:"+ baseDao );
        baseDao.save();
    }

}
----------------------------------------------
@Service
public class BookService extends BaseService<BookService> {
}
----------------------------------------------------
@Service
public class UserService extends BaseService<UserService> {
}
------------------------------------------------------
测试结果
public class IOCTest {
    ApplicationContext ioc = new ClassPathXmlApplicationContext("applicationContext.xml");
    @Test
    public void test1(){
        BookService bookService = ioc.getBean(BookService.class);
        UserService userService = ioc.getBean(UserService.class);

        bookService.save();// BookDao。。。保存图书
        userService.save();// UserDao。。。保存用户
    }

}

类似于动态绑定
image-1664329547930

结尾

1、容器启动,创建所有单实例bean
2、AutoWired自动装配的时候,是从容器中找这些符合要求的bean
3、ioc.getBean("bookServlet");也是从容器中找到这个bean
4、容器中包括了所有的bean;
5、调试Spring的源码,容器到底是什么?其实就是一个map;
6、这个map保存所有创建的bean,并提供外界获取功能...
7、探索,单实例的bean都保存在哪个map中【源码---扩展内容】
8、源码调试的思路:
    从helloworld开始的;给helloworld每一步关键步骤打上断点,进去看里面都做了什么工作?
    怎么知道哪些方法都是干什么的
        1、翻译这个方法
        2、放行这个方法,看控制台,看debug的每一个变量的变化
        3、看方法的注释
学到的一点:
    1、规范注释
    2、规范方法名和类名(见名知意)

评论