第1节 Spring IoC基础
1.1 BeanFactory与ApplicationContext区别
![](https://i-blog.csdnimg.cn/blog_migrate/9786dc22f4c1c17508d90379c1e75fef.png)
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <!--配置Spring ioc容器的配置文件--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!--使用监听器启动Spring的IOC容器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
从配置类启动容器
<!DOCTYPE web-app PUBLIC"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN""http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app><display-name> Archetype Created Web Application </display-name><!-- 告诉 ContextloaderListener 知道我们使⽤注解的⽅式启动 ioc 容器 --><context-param><param-name> contextClass </param-name><paramvalue> org.springframework.web.context.support.AnnotationConfigWebApplicationContext </param-value></context-param><!-- 配置启动类的全限定类名 --><context-param><param-name> contextConfigLocation </param-name><param-value> com.lagou.edu.SpringConfig </param-value></context-param><!-- 使⽤监听器启动 Spring 的 IOC 容器 --><listener><listenerclass> org.springframework.web.context.ContextLoaderListener </listenerclass></listener>
1.2 纯xml模式
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.5</version> </dependency>
把原来的bean.xml修改成为spring配置文件,修改名字为applicationContext.xml,加入spring的文件头
<?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 https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--方式一:使用无参构造器(推荐)--> <bean id="connectionUtils" class="com.lagou.edu.utils.ConnectionUtils"></bean>
那么在实际开发中,尤其早期的项⽬没有使⽤Spring框架来管理对象的创建,但是在设计时使⽤了
<!--方式二:静态方法--> <!--<bean id="connectionUtils" class="com.lagou.edu.factory.CreateBeanFactory" factory-method="getInstanceStatic"/>-->
<!--方式三:实例化方法--> <!--<bean id="createBeanFactory" class="com.lagou.edu.factory.CreateBeanFactory"></bean> <bean id="connectionUtils" factory-bean="createBeanFactory" factory-method="getInstance"/>-->
创建CreateBeanFactory,进行测试
package com.lagou.edu.factory; import com.lagou.edu.utils.ConnectionUtils; public class CreateBeanFactory { public static ConnectionUtils getInstanceStatic() { return new ConnectionUtils(); } public ConnectionUtils getInstance() { return new ConnectionUtils(); } }
测试方法
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao"); System.out.println("accountDao:" + accountDao); AccountDao accountDao1 = (AccountDao) applicationContext.getBean("accountDao"); System.out.println("accountDao1:" + accountDao1); Object connectionUtils = applicationContext.getBean("connectionUtils"); System.out.println(connectionUtils);
结果
scope:定义bean的作用范围
singleton:单例,IOC容器中只有一个该类对象,默认为singleton
prototype:原型(多例),每次使用该类的对象(getBean),都返回给你一个新的对象,Spring只创建对象,不管理对象
<bean id="connectionUtils" class="com.lagou.edu.utils.ConnectionUtils" scope="prototype"></bean>
public void init() { System.out.println("初始化方法....."); } public void destory(){ System.out.println("销毁方法....."); }
在applicationContext.xml中调用
<bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcTemplateDaoImpl" scope="singleton" init-method="init" destroy-method="destory">
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml"); applicationContext.getBean("accountDao"); System.out.println("accountDao:" + accountDao); AccountDao accountDao1 = (AccountDao) applicationContext.getBean("accountDao"); System.out.println("accountDao1:" + accountDao1); Object connectionUtils = applicationContext.getBean("connectionUtils"); System.out.println(connectionUtils); applicationContext.close();
![](https://i-blog.csdnimg.cn/blog_migrate/41c85d5b2cee3fca14698d3667166552.png)
JdbcAccountDaoImpl加入属性和set方法和构造函数
private ConnectionUtils connectionUtils; private String name; private int sex; private float money; public void setConnectionUtils(ConnectionUtils connectionUtils) { this.connectionUtils = connectionUtils; } public void setName(String name) { this.name = name; } public void setSex(int sex) { this.sex = sex; } public void setMoney(float money) { this.money = money; }
<bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcTemplateDaoImpl" scope="singleton" init-method="init" destroy-method="destory"> <property name="ConnectionUtils" ref="connectionUtils"/> <property name="name" value="zhangsan"/> <property name="sex" value="1"/> <property name="money" value="100.3"/> </bean>
debug 模式
构造器注入
在JdbcAccountDaoImpl加入构造器
public JdbcAccountDaoImpl(ConnectionUtils connectionUtils, String name, int sex, float money) { this.connectionUtils = connectionUtils; this.name = name; this.sex = sex; this.money = money; }
xml配置文件
<bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcTemplateDaoImpl" scope="singleton" init-method="init" destroy-method="destory"> <constructor-arg index="0" ref="connectionUtils"/> <constructor-arg index="1" value="zhangsan"/> <constructor-arg index="2" value="1"/> <constructor-arg index="3" value="100.5"/> </bean>
debug
构造器index属性不太方便,因为要核对下标,可以使用name,<!--name:按照参数名称注入,index按照参数索引位置注入-->
<constructor-arg name="connectionUtils" ref="connectionUtils"/> <constructor-arg name="name" value="zhangsan"/> <constructor-arg name="sex" value="1"/> <constructor-arg name="money" value="100.6"/>
set设置
在JdbcAccountDaoImpl加入
private String[] myArray; private Map<String,String> myMap; private Set<String> mySet; private Properties myProperties; public void setMyArray(String[] myArray) { this.myArray = myArray; } public void setMyMap(Map<String, String> myMap) { this.myMap = myMap; } public void setMySet(Set<String> mySet) { this.mySet = mySet; } public void setMyProperties(Properties myProperties) { this.myProperties = myProperties; }
<bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcTemplateDaoImpl" scope="singleton" init-method="init" destroy-method="destory">
<property name="myArray"> <array> <value>array1</value> <value>array2</value> <value>array3</value> </array> </property> <property name="myMap"> <map> <entry key="key1" value="value1"/> <entry key="key2" value="value2"/> </map> </property> <property name="mySet"> <set> <value>set1</value> <value>set2</value> </set> </property> <property name="myProperties"> <props> <prop key="prop1">value1</prop> <prop key="prop2">value2</prop> </props> </property> </bean>
1.3 xml与注解相结合模式
<!--第三方jar中的bean定义在xml中--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean>
在ConnectionUtils注入
private DataSource dataSource; private void setDataSource(DataSource dataSource){ this.dataSource=dataSource; }
使用
![](https://i-blog.csdnimg.cn/blog_migrate/874a39833e2a0177c816e33ccf7e779f.png)
配置依赖
<bean id="connectionUtils" class="com.lagou.edu.utils.ConnectionUtils"> <property name="dataSource" ref="dataSource"></property> </bean>
<bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcTemplateDaoImpl" scope="singleton" init-method="init" destroy-method="destory"><property name="ConnectionUtils" ref="connectionUtils"/></bean>
@Component("accountDao") public class JdbcAccountDaoImpl implements AccountDao {
<bean id="transferService" class="com.lagou.edu.service.impl.TransferServiceImpl">
<!--set+ name 之后锁定到传值的set方法了,通过反射技术可以调用该方法传入对应的值-->
<property name="AccountDao" ref="accountDao"></property>
</bean>
@Component("transferService") public class TransferServiceImpl implements TransferService {
<!--事务管理器-->
<bean id="transactionManager" class="com.lagou.edu.utils.TransactionManager">
<property name="ConnectionUtils" ref="connectionUtils"/>
</bean>
@Component("transactionManager")
public class TransactionManager {
<!--代理对象工厂-->
<bean id="proxyFactory" class="com.lagou.edu.factory.ProxyFactory">
<property name="TransactionManager" ref="transactionManager"/>
</bean>
@Component("proxyFactory")
public class ProxyFactory {
<bean id="connectionUtils" class="com.lagou.edu.utils.ConnectionUtils"></bean>
@Component("connectionUtils")
public class ConnectionUtils {
![](https://i-blog.csdnimg.cn/blog_migrate/184f92aead66e945911d8f65a792b04f.png)
根据分层不同可以将相应的@Component注解改为@Reposity
@Reposity("accountDao")
public class JdbcAccountDaoImpl implements AccountDao {
原来的set方法注入 private ConnectionUtils connectionUtils; public void setConnectionUtils(ConnectionUtils connectionUtils){ this.connectionUtils=connectionUtils; }改造如下
@Autowired private ConnectionUtils connectionUtils;
@Autowired按照类型进行注入,如上代码所示,这样装配回去spring容器中找到类型为AccountDao的类,然后将其注⼊进来。这
public class TransferServiceImpl {@Autowired@Qualifier ( name = "jdbcAccountDaoImpl" ) //指定具体idprivate AccountDao accountDao ;}
@Resource
@Resource 注解由 J2EE 提供,需要导⼊包 javax.annotation.Resource。
public class TransferService {@Resourceprivate AccountDao accountDao ;@Resource ( name = "studentDao" )private StudentDao studentDao ;@Resource ( type = "TeacherDao" )private TeacherDao teacherDao ;@Resource ( name = "manDao" , type = "ManDao" )private ManDao manDao ;}
<dependency><groupId> javax.annotation </groupId><artifactId> javax.annotation-api </artifactId><version> 1.3.2 </version></dependency>
配置识别注解和xml,引入spring-context空间
xmlns:context="http://www.springframework.org/schema/context"http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd<!--开启注解扫描,base-package指定扫描的包路径--> <context:component-scan base-package="com.lagou.edu"/>
再一次进行测试,转账成功,金额正确
1.4 纯注解模式
@PropertySource,引⼊外部属性配置⽂件
package com.lagou.edu; import com.alibaba.druid.pool.DruidDataSource; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.*; import javax.sql.DataSource; /** * @author 应癫 */ // @Configuration 注解表明当前类是一个配置类 @Configuration @ComponentScan({"com.lagou.edu"}) @PropertySource({"classpath:jdbc.properties"}) /*@Import()*/ public class SpringConfig { @Value("${jdbc.driver}") private String driverClassName; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean("dataSource") public DataSource createDataSource(){ DruidDataSource druidDataSource = new DruidDataSource(); druidDataSource.setDriverClassName(driverClassName); druidDataSource.setUrl(url); druidDataSource.setUsername(username); druidDataSource.setPassword(password); return druidDataSource; } }
测试类中启动spring-ioc容器
// 通过读取classpath下的xml文件来启动容器(xml模式SE应用下推荐) ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao"); System.out.println(accountDao);
web容器中启动spring-ioc容器
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <!--告诉ContextloaderListener知道我们使用注解的方式启动ioc容器--> <context-param> <param-name>contextClass</param-name> <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value> </context-param> <!--配置启动类的全限定类名--> <context-param> <param-name>contextConfigLocation</param-name> <param-value>com.lagou.edu.SpringConfig</param-value> </context-param> <!--使用监听器启动Spring的IOC容器--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> </web-app>
测试转账成功,金额正确