基于xml的Spring应用
SpringBean的配置详解
-
Bean的id(后期会自动转化为name)和全限定名配置
不配置id之时会默认将class的路径名作为id后期再转化为name
<bean id="" class="">
-
通过name设置Bean的别名
getBean(name)
name="name1 [,name2,...]"设置的是别名,使用逗号分隔多个别名<bean name="">
-
Bean的作用范围
当BeanFactory作为容器时为singleton/prototype
singleton(默认值):单例,Spring容器创建之时,便会进行Bean的实例化,并存储到容器内部的单例池,每次使用getBean都会从单例池中获取相同的Bean实例;
singletonObjects:单例池
prototype:原型,Spring容器初始化时不创建Bean实例,每次使用getBean时都会创建一个全新的Bean实例
<bean scope="">
-
Bean的实例化时机,是否延迟加载(本质是单例的)
当BeanFactory作为容器时无效
<bean lazy-init="true">
-
Bean实例化后自动执行的初始化方法,method指定方法名
<bean init-method="">
-
Bean实例销毁前自动执行的方法,method指定方法名
<bean destroy-method="">
-
设置自动注入模式
byName:<bean id="userService" class="com.xiaowan.service.Impl.UserServiceImpl" autowire="byName"> </bean> <bean id="userDao" class="com.xiaowan.dao.impl.UserDaoImpl"> </bean> ``` 名字一定要对应上,例如上面的Bean类userDao的name为userDao则在UserServiceImpl中设置userDao的方法一定得为:setUserDao,即set+(首位大写)Bean类id/name btType: 可以忽略名字进行类型匹配,但只能一个类型的Bean配置只能有一个
常用的有:
byType
byName
<bean autowrie="">
-
指定哪个工厂Bean的哪个方法完成Bean的创建
<bean factory-bean="" factory-method=""/>
Spring Bean的实例化配置
本身整体使用的即为工厂模式,以下描述的是工厂模式在制造bean的时候用到的方式(构造方法或者嵌套工厂模式)
Spring实例化方式:
-
构造方式实例化:底层通过构造方法对Bean进行实例化
<bean id="userDao" class="com.xiaowan.dao.impl.UserDaoImpl"/> ``` 以上方式即为默认的无参构造方法实例化Bean 为UserDaoImpl添加有参构造: ```java public UserServiceImpl(String name) { System.out.println("UserServiceImpl有参构造,接收参数name:"+name); } ``` xml更改为有参构造并传参 ```xml <bean id="userService" class="com.xiaowan.service.Impl.UserServiceImpl"> <constructor-arg name="name" value="123"> </constructor-arg> <property name="userDao" ref="userDao"> </property> </bean> ``` > 该方法不常用 > <b style="color:red">constructor-arg可以在bean创造时所需要传参的地方都能使用</b>
-
工厂方式实例化:底层通过调用自定义的工厂方法对Bean进行实例化
-
静态工厂方法实例化Bean
使用自定义工厂中的静态方法的内部产生Bean,并将其交予Spring容器管理
即调用方法时无需产生类对象,直接通过类访问进行调用方法实例化bean
public class MyBeanFactory1 { public static UserDao userDao(){ return new UserDaoImpl(); } } ``` ```xml <bean id="userDao1" class="com.xiaowan.factory.MyBeanFactory1" factory-method="userDao"> </bean> ``` **Bean实例化过程中无需实例化MyBeanFactory1直接配置类中实例化UserDaoImpl的方法userDao()即可完成Spring容器托管** 该方法的优点: - Bean创建之前可以进行一些其他的业务逻辑操作 - 方便将第三方Bean交予Spring容器托管 如jdbc中Connection类便是通过DrivenManager.getConnection()方法进行实例化,这里便可以通过静态工厂对Connection进行Spring容器托管
-
-
实例工厂方法实例化Bean
在工厂中的非静态方法中产生的返回值为Bean,并交予Spring容器管理
即必须实例化工厂类对象,才能访问方法进行Bean的实例化public class MyBeanFactory2 { public UserDao userDao(){ return new UserDaoImpl(); } } ``` ```xml <bean id="myBeanFactory2" class="com.xiaowan.factory.MyBeanFactory2"> </bean> <bean id="userDao2" factory-bean="myBeanFactory2" factory-method="userDao"> </bean> ``` **Bean实例化时需要先实例化工厂对象MyBeanFactory2才能调用方法进行Bean的实例化,且配置时需要先声明工厂类,并在Bean配置中使用factory-bean映射对应的工厂类实例,再通过factory-method中配置的方法的返回对象实例化Bean** > 当以上两种方法实现有参数的方法时使用constructor-arg配置参数 > 当配置了factory-method后则实例化的Bean对象为factory-method所指定的方法的返回的Bean对象
-
实现FactoryBean规范延迟实例化Bean
当Bean需要被使用时才会实例化(原先为Spring容器被创建时则在单例池中立马进行Bean实例化),即为延迟实例化,在该过程中,单例池中所实例化的对象为包含对应方法的工厂类,而Bean需要准备使用时(执行getBean()时),Bean的实例化会发生在工厂单例缓存池中(factoryBeanObjectCache)进行实例化并调取
public class MyBeanFactory3 implements FactoryBean<UserDao> { @Override public UserDao getObject() throws Exception { return new UserDaoImpl(); } @Override public Class<?> getObjectType() { return UserDao.class; } } ``` ```xml <bean id="userDao3" class="com.xiaowan.factory.MyBeanFactory3"> </bean> ``` 配置中实例化的并不是com.xiaowan.factory.MyBeanFactory3的对象,而是getObject()中返回的对象,类似与factory-method="getObject" > 在底层中常用该方式
-
Bean的依赖注入配置
ref:用于注入引用对象,且该引用对象在配置文件中已进行配置(即容器中的某一个Bean注入容器中的另外一个Bean)
value:用于注入普通属性
set方法注入:<property name="userDao" ref="userDao"></property> ``` > 构造Bean方法注入: ```xml <constructor-arg name="name" value="123"></constructor-arg> ``` 集合属性注入:例如List、Map、Properties等
-
List
list内为普通对象:
private List<String> stringList; public void setStringList(List<String> stringList) { this.stringList = stringList; } //用于遍历list @Override public void showList(){ stringList.forEach(System.out::println); } ``` ```xml <bean id="userServiceList" class="com.xiaowan.service.Impl.UserServiceImpl"> <property name="stringList"> <list> <value>aaa</value> <value>bbb</value> </list> </property> </bean> ``` list内为引用对象 ```java private List<UserDao> userDaoList; public void setUserDaoList(List<UserDao> userDao) { this.userDaoList = userDao; } ``` ```xml <bean id="userServiceList" class="com.xiaowan.service.Impl.UserServiceImpl"> <property name="userDaoList"> <list> <bean class="com.xiaowan.dao.impl.UserDaoImpl"> </bean> </list> </property> </bean>
三种getBean方法:
-
方法定义 | 返回值和参数 | 前提条件 |
---|---|---|
Object getBean(String beanName) | 根据beanName从容器获取Bean实例,返回值为Object,需要强转 | 容器中Bean唯一 |
T getBean(Class type) | 根据Class类型从容器中获取Bean实例,返回值为Class类型实例 | 容器中Bean类型唯一 |
T getBean(String beanName,Class type) | 根据beanName从容器获取Bean实例,返回值为Class类型实例 | 无 |
配置非自定义的Bean
非自定义Bean:第三方jar包
明确两点:
-
被配置的Bean的实例化方式时什么(无参构造、有参构造、静态工厂还是实例工厂等)
-
被配置的Bean是否需要注入必要属性
例1-Druid数据源的配置:
导入Druid坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.18</version>
</dependency>
不交于Spring容器管理的写法(传统写法):
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("");
dataSource.setUrl("");
dataSource.setUsername("");
dataSource.setPassword("");
交予Spring容器管理写法:
-
判断Bean的实例化方式
查看源码是否有构造方法(有参、无参)
该源码存在无参构造该Bean需要注入必要属性
public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; }
public DruidDataSource() { this(false); }
-
根据set方法的命名规则设置参数配置
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value=""> </property> <property name="url" value=""> </property> <property name="username" value=""> </property> <property name="password" value=""> </property> </bean>
配置完毕
例2-JDBC:Connection的配置
导入connection的坐标
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
传统写法:
Class.forName("");
Connection connection = DriverManager.getConnection("");
交予Spring容器管理写法:
-
查看Bean实例化方式
该源码为接口,无无参构造
Connection为静态工厂方式进行实例化,由DriverManager作为静态工厂通过静态方法进行实例化
该Bean需要注入的必要属性名称@CallerSensitive public static Class<?> forName(String className) throws ClassNotFoundException { Class<?> caller = Reflection.getCallerClass(); return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }
-
配置
<bean id="clazz" class="java.lang.Class" factory-method="forName"> <constructor-arg name="className" value=""> </constructor-arg> </bean> <bean id="connection" class="java.sql.Connection" factory-method="getConnection"> <constructor-arg name="url" value=""></constructor-arg> <constructor-arg name="user" value=""></constructor-arg> <constructor-arg name="password" value=""></constructor-arg> </bean>