实验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。。。保存用户
}
}
类似于动态绑定
结尾
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、规范方法名和类名(见名知意)