Spring中Bean对象创建方式的梳理
____刚开始接触Spring框架的时候,觉得他的IOC反转控制巧妙得很,不由得兴趣盎然动力满满。进一步学习过后才发现里面Bean对象的创建让人眼花缭乱,容易让人蒙圈(对初学者而言,大佬请加速通过)。从一开始在代码里直接用工厂模式创建,到用XML配置,用注解,用配置类配置等,今天在这里理清一下Bean对象创建的集中方式.
第一种:创建工厂生产Bean对象
____首先最原始的方法是通过自己建立工厂类,读取properties配置文件里的类,通过反射创建出类对象并将其放入自建的Map容器中,在需要用到bean的地方通过工厂的getBean方法直接获取。代码如下:
//这是properties配置文件里的内容
accountService=com.ilcosmo.service.impl.AccountServiceImpl
accountDao=com.ilcosmo.dao.impl.AccountDaoImpl
//这是工厂类的内容
private static Properties props;
private static Map<String,Object> beans;
static {
try {
props = new Properties();
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
beans = new HashMap<String,Object>();
Enumeration keys = props.keys();
while (keys.hasMoreElements()){
String key = keys.nextElement().toString();
String beanPath = props.getProperty(key);
Object value = Class.forName(beanPath).newInstance();
beans.put(key,value);
}
}catch (Exception e) {
throw new ExceptionInInitializerError("初始化properties失败");
}
}
//需要bean对象时,直接这样调用,即可获取对应的bean对象
private IAccountDao accountDao = (IAccountDao)BeanFactory.getBean("accountDao");
第二种:通过XML文件配置
____这种配置包含基础配置和注入配置。配置后在类里通过spring的容器获得bean对象,或者通过set方法获取。
基础配置:即只靠默认构造方法生成bean对象,无构造参数
____直接选择基础的xml,配置bean标签中的id属性和class属性即可,其他scope等属性后面单独讲实例时再说。如:
//id即为获取bean对象时用的标识,class为bean对象对应的全限定类名
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 把对象的创建交给spring管理-->
<bean id="accountService" class="com.ilcosmo.service.impl.AccountServiceImpl"></bean>
<bean id="accountDao" class="com.ilcosmo.dao.impl.AccountDaoImpl"></bean>
</beans>
注入配置:在生成bean对象时同时加入对象的属性
这里又有两种方式注入数据,一是通过set方法注入(常用)
____这里能注入的属性包括基本数据类型和String类型、其他bean对象、复杂类型。基本数据类型和String类型、其他bean对象直接用bean标签里的子标签,需要配置property的属性为name和value或者ref(注入其他bean对象时使用)。复杂类型如集合等这里先不说。如:
//使用Spring jdbc时的bean.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="jdbcTeamplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="ds"></property>
</bean>
<bean id="ds" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="url" value="jdbc:mysql://localhost:3306/test"></property>
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="username" value="root"></property>
<property name="password" value=""></property>
</bean>
</beans>
二是通过构造方法注入
____这种方法有很大的弊端,在不需要对象所有属性都有值时也必须得输入对应的值(构造方法的要求,没有要求的入参,无法调用构造方法)。如:
//省略其他重复内容
<bean id="accountService" class="com.ilcosmo.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="test"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
第三种:通过注解配置
____注解配置也需要配置xml,xml文件的头于前面单纯靠xml配置的头部内容有差别。这里xml主要配置spring创建容器时需要扫描的包,在包里对应的类上添加@Component后,spring框架即可在读取完配置文件之后在容器里创建该类对应的bean对象。除此外,spring还按功能给我们提供了三个更细化的注解:@service @Controller @repository,分别表示业务层的bean,表现层的bean,持久层的bean。
____配置后在类中同样通过spring容器获取bean对象。
____注解配置里还有参数注入的相关注解,后面再慢慢搞搞。
//bean.xml文件的内容
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 告知spring在创建容器时要扫描的包 -->
<context:component-scan base-package="com.ilcosmo"></context:component-scan>
</beans>
//代码里业务层bean的注解
@Service("accountService")
//@Scope("prototype")
public class AccountServiceImpl implements IAccountService {}
第四种:通过配置类配置
____这种方式实际也是通过注解配置,只是将xml里的注解转移到了一个类里面。新建一个类,通过注解@Configuration将其标注为注解类,并用@ComponentScan(“com.ilcosmo”)指定spring创建容器时需要扫描的包,相当于xml中的<context:component-scan base-package=“com.ilcosmo”</context:component-scan>配置,在获取spring容器时,也转用new AnnotationConfigApplicationContext(SprinConfigration.class)来获取容器,其中的入参即是之前配置的配置类。如:
//配置类
@Configuration
@ComponentScan("com.ilcosmo")
public class SprinConfigration {
@Bean//作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中
//name:用于指定bean的id,当不写时默认时方法名
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
@Bean(name = "dataSource")
public DataSource createDataSource(){
try {
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass("com.mysql.jdbc.Driver");
ds.setJdbcUrl("jdbc:mysql://localhost:3306/test");
ds.setUser("root");
ds.setPassword("");
return ds;
} catch (Exception e){
throw new RuntimeException(e);
}
}
}
总结
____第一中用工厂创建获取bean对象的方式开发中一般不用,第二种xml配置一般适合生成引入jar包中bean对象时使用,第三种注解的方法一般适合生成自己类bean对象时使用,第四种和第三种一样。
____有错误或不当希望轻喷,小白身子弱胆子小扛不住。理解有误的地方欢迎指指点点。