Spring Bean对象
1.1 Bean对象的命名
当我们把对象交给Bean容器管理时都要给他配一个名字,使用id或name属性,如下在Bean标签中
<bean id="date1" class="java.util.Date"/>
当然我们不指定的话,系统会默认制定一个,规则是首字母小写的类名,如date
1.2 Bean对象的实例化
Spring容器创建Bean对象的方法有如下3种方式:
1. 通过构造器实例化Bean对象.
<bean id="date1" class="java.util.Date"/>
2. 通过静态工厂方法实例化Bean对象.
<bean id="c1" class="java.util.Calendar" factory-method="getInstance" />
这里代表通过Calendar对象的getInstance静态方法获得此对象
3. 通过实例工厂方法实例化Bean对象.
<bean id="date" factory-bean="c1" factory-method="getTime"/>
此处我们通过factory-bean标签制定一个实例化的对象的方法来创建Date对象
1.3 Bean对象的作用域
我们就不按照书本上解释了,所谓Bean对象的作用域指的就是它在内存中有几份,一般默认的作用域是单例模式,也就是创建出来一份取用都只是这一个,另一种常用的是多例模式,也就是每次获取都是一个新建的实例.还有需要注意的是单例模式下对象的创建销毁都由Spring来管理,而多例模式下spring只管创建,不管销毁.
1)singleton(单例):每次从容器获取返回的都是一个对象(内存中此类的实例只有一份),Spring中bean的默认作用域
2)prototype(多例):每次从容器获取都创建一个新的类的实例销毁不由Spring管理
<bean id="helloService" class="memory.HelloService"
scope="prototype"
init-method="init"
destroy-method="destroy"/>
<!-- 我们可以在此指定init和destroy也就是创建和销毁的方法,也可以不指定 -->
注:面试的时候可能会被问到,单例模式有什么坏处吗?
答:单例设计在对内部实例变量进行非原子操作有可能有线程安全问题.
以后我们有可能讲到单例模式如何设计?留个期待吧
1.4 Bean对象的延迟加载
延迟加载指的就是先不要让Spring创建出配置的对象,当需要时再创建.一般我们将一些大的不常用的对象设定延迟加载,这样做的好处是系统启动快,内存开销小.
单独为一个对象延迟加载就在bean标签中加上 lazy-init=“true” 属性
我们也可以进行全局的延迟加载,那么就在beans标签中加上 default-lazy-init="true"
而当我们有些对象需要立即加载,可以将延迟加载设为false
举个例子
<beans
default-lazy-init="true"
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
.....
<bean
id="date"
class="java.util.Date"
lazy-init="false"/>
</beans>
下面填一下上节留下的坑---DI(Dependency Injection)依赖注入
Spring Bean 依赖
2.1 依赖注入DI
简单直白:就是给参数注入值
我们在创建对象时通常会使用构造方法或者set方法给属性注入值,使用Spring管理对象同样的也有对应的两种方式
Spring 容器中的Bean对象通常会存在一定的依赖关系,而这种依赖关系的实现在Spring 框架中要借助于DI机制。其中DI就是借助对象管理对象依赖关系的一个过程。
Spring中提供的依赖注入方式有构造注入和set注入,其中构造注入就是借助构造方法的参数实现对类中属性值的注入,set注入就是借助set方法的参数实现其属性值的注入。
Spring 依赖注入时,可以实现基本值的注入,Bean对象的注入,集合的注入,spring表达式方式的注入等等。
set注入的配置(重点)
<!-- 在bean标签中对需要注入的属性加入property标签 -->
<bean id="dataSource1" class="com.company.spring.util.DataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///test"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
构造注入(了解)
<!--加入constructor-arg标签,spring会根据参数顺序注入-->
<bean id="dataSource2" class="com.company.spring.util.DataSource">
<constructor-arg value="com.mysql.jdbc.Driver"/>
<constructor-arg value="jdbc:mysql:///test"/>
<constructor-arg value="root"/>
<constructor-arg value="root"/>
</bean>
2.2高级注入
除了注入一些单个值或对象的注入,还有复杂类型注入的方式,如数组,集合.再次挖坑(别打我),放到下一节讲
2.3 自动装配
简单直白:让Spring直接从bean容器中找到属性对应的的合适的bean对象自动注入进去
Spring IOC容器可以自动装配(autowire)相互协作bean之间的关联关系,不用自己写set注入构造注入
autowire可以针对单个bean进行设置,autowire的方便之处在于减少xml的注入配置
Spring 配置文件中通过bean元素的autowire属性指定自动装配规则,一共有四种类型值
属性值 | 描述 | |
---|---|---|
1. | no | 禁用自动配置(默认) |
2. | byName | 按名字自动装配(重点掌握),有名字相同类型不同的风险 |
3. | byType | 按类型自动状态(重点掌握),但有多个类型时会出错 |
4. | constructor | 与byType类似,不同之处在于它应用于构造器参数。 |
例如:
<bean id="jdbcTemplate3"
class="com.company.spring.injection.JdbcTemplate"
autowire="byType">
</bean>
<!--注:byType时有类型相同的对象会报错找到重复类型的对象
No qualifying bean of type 'beans.DataSource' available: expected single matching bean but found 2: dataSource,dataSource1-->
实际当中自动装配并不常用,了解,了解(估计又有人要打我)
今日扩展内容
==================================================
我们就来模拟一下如何通过反射动态调用方法模拟spring如何找到的set方法
Scanner sc=new Scanner(System.in);
System.out.println("please input class");
//java.util.Date
String pkgCls=sc.nextLine();
System.out.println("please input method");
//getTime
String methodName=sc.nextLine();
//1.构建类对象
Class<?> c=Class.forName(pkgCls);
//2.获取类中方法对象
Method m=c.getDeclaredMethod(methodName);
//3.执行类的对象的方法
Object obj=c.newInstance();
Object result=m.invoke(obj);
System.out.println(result);
sc.close();