问题
在传统业务中我们会在service中调用
UserDao userDao = new UserDaoImpl();
这样我们的业务就会与dao的实现关联在了一起,当我们的组件需要增加或者修改时 怎么办呢?我们就会去 修改实现类增加实现类等操作 ,然后自己再new 一个impl来实现要求,
如果我们不再new UserDaoImpl()只是组装private UserDao userDao;并在业务里添加getter setter 或者构造器来接收一个对象就是spring里面的bean 并把创建bean的权利交给spring工厂就是容器IOC(此时我们不管对象的创建),我们只需要等待接收bean就可以 这就是依赖注入DI
### 核心组件
1:ClassPathXmlApplicationContext它用来获取配置工厂环境,此环境用来生产bean 并未我们的getter constructor 的属性赋值
2: ApplicationContext 是1的接口1实现了2
具体用法
1:用来获取环境就是开启工厂
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
2:获取生产的bean
AutoComonent autoComonent1 = (AutoComonent) context.getBean("auto");
核心配置文件applicationContext.cml
<?xml version="1.0" encoding="UTF-8"?>
<!--约束
dtd约束: xxx.dtd 用来约束文件的 标签 顺序 属性 格式等
xsd约束: xxx.xsd 用来约束文件的 标签 顺序 属性 格式等
-->
<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 生产的组件 -->
<!-- UserDAOImpl组件 id="组件标识" class="组件类型" -->
</beans>
生产不同数据类型并且赋值
普通bean的上产和赋值
生产一个 名为userBean的bean 并传给一个实现类的犬类路径名
为什么是实现累的全类路径名是因为 spring底层会通过
<bean class="xx.xx.xxx.XXX" id="xxx">
// 反射
String classpath="com.zhj.domain.User";
Class user = Class.forName(classpath);
Constructor constructor = user.getConstructor();
User o = (User)constructor.newInstance();
来创建出来我们需要的bean
<bean id="userBean" class="com.qf.dao.UserDaoImpl">
</bean>
<bean id="userService" class="com.qf.service.UserServiceImpl">
<!--赋值给getter setter-->
<!--普通bean用name属性注明bean标签中产生的bean的id ref用来引用-->
<property name="userDao" ref="userBean"></property>
<!--此处的userDao为serviceImpl里面组装的dao 就是等待依赖注入的那个-->
</bean>
<!--setter注入其他类型的的方式-->
<bean id="setDi01" class="com.qf.di.SetComponent">
<!--数字用 value赋值-->
<property name="id" value="2"></property>
<property name="name" value="****"></property>
<property name="gender" value="true"></property>
<property name="userDao" ref="userBean"></property>
<!--properties赋值-->
<property name="prop">
<props>
<prop key="url">jdbc:mysql....</prop>
<prop key="driver">com.mysql.jdbc.Driver</prop>
<prop key="username">username</prop>
</props>
</property>
<!--map赋值-->
<property name="map">
<map>
<entry key="username" value="root"></entry>
<entry key="password" value="123"></entry>
</map>
</property>
<!--set-->
<property name="set">
<set>
<value>张三</value>
<value>李四</value>
<value>张三</value>
<!--此处与list不同list可以引入一个bean set类型不可以引入`在这里插入代码片`-->
</set>
</property>
<!--list-->
<property name="list">
<list>
<value>flksdj</value>
<ref bean="userBean"></ref>
</list>
</property>
</bean>
构造器注入方式
<!--构造器-->
<bean id="constructor" class="com.qf.di.ConsComponent" scope="prototype">
<constructor-arg index="0" type="java.lang.Integer" value="32"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="hfh"></constructor-arg>
</bean>
bean的作用域单例:scope=“singleton”
他是默认的作用域 因为我们绝大部门用到的是默认的作用域无论你获取
getBean多少次他都是唯一的,而且spring会投入很大额经历都在管理他
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
AutoComonent autoComonent1 = (AutoComonent) context.getBean("auto");
AutoComonent autoComonent2 = (AutoComonent) context.getBean("auto");
System.out.println("@@@@@@@@@@@@@"+autoComonent1);
System.out.println("$$$$$$$$$$$$"+autoComonent2);
输出结果:
@@@@@@@@@@@@@com.qf.di.AutoComonent@4eb7f003
$$$$$$$$$$$$com.qf.di.AutoComonent@4eb7f003
我们会发现hashCode一样说明此处两次获取的bean是同一个
bean的作用域多例: scope=“prototype”
我们可以手动修改bean 的作用域
<bean id="constructor" class="com.qf.di.ConsComponent" scope="prototype">
<constructor-arg index="0" type="java.lang.Integer" value="32"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="hfh"></constructor-arg>
</bean>
运行结果
@@@@com.qf.di.ConsComponent@51c8530f
$$$$$$$$$$$$$$$$$$com.qf.di.ConsComponent@7403c468
此时hashCode不一样就说明此处获取到的两个bean并非同一个
多例spring工厂不会化太多精力去管理他因此他的存活期与工厂无关他在被调用时存活 而且他没有destroy期
工厂Bean
他用来生产那些复杂的bean,而且他只有这一个作用,而spring容器可以生产任意类型的bean,但是有一种类型她不适合他生产,就是复杂类型,
带环境配置的bean他spring容器生产出来的将会是一个空的bean没有实际作用例如SqlSessionFactory 因为Sql需要url driver username password 等环境
因此我们就需要工厂Bean来帮忙
public class MySqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>{
// 主体逻辑 完成某种复杂对象的生产
// 会在首次使用时调用
public SqlSessionFactory getObject() throws Exception {
System.out.println("MyFactoryBean create SqlSessionFactory~~~");
// 构建过程
Reader reader = Resources.getResourceAsReader("configuration.xml");
return new SqlSessionFactoryBuilder().build(reader);
}
// 返回 某种复杂对象的 类对象
@Override
public Class<?> getObjectType() {
return SqlSessionFactory.class;
}
// 控制复杂对象的创建模式
@Override
public boolean isSingleton() {
return true;
}
public MySqlSessionFactoryBean() {
System.out.println("mySqlSessionFactory Create~~~");
}
}