<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 注册一个Cat对象-->
<bean class="com.zsc.pojo.Cat" id="cat" p:nick="花花" p:color="黑色"/>
<bean class="com.zsc.pojo.UserBean" id="user">
<!-- 设值注入 -->
<property name="cat" ref="cat">
<!--<bean class="com.zsc.pojo.Cat" />-->
</property>
<property name="favorites">
<array>
<value>篮球</value>
<value>爬山</value>
<value>逛街</value>
</array>
</property>
<property name="cats">
<list>
<bean class="com.zsc.pojo.Cat" p:nick="小花1" p:color="红色"/>
<bean class="com.zsc.pojo.Cat" p:nick="小花2" p:color="绿色"/>
<bean class="com.zsc.pojo.Cat" p:nick="小花3" p:color="黄色"/>
</list>
</property>
<property name="map" >
<map>
<entry key="name1" value="张三1"/>
<entry key="name2" value="张三2"/>
<entry key="name3" value="张三3"/>
</map>
</property>
<property name="props">
<props>
<prop key="username" >root</prop>
<prop key="password">123</prop>
</props>
</property>
</bean>
</beans>
1. IOC控制反转
IOC本质上是一个概念,是一种思想,控制反转就是对对象控制权的转移,SpringIOC容器创建对象,然后把对象的使用权交出去
2. 基于XML配置文件方式实现
2.1 基本使用
a.引入依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.17.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
b. 添加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 http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
c.注册Bean
将需要被Ioc容器管理的类型通过<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">
<!-- 添加需要被容器管理的内容-->
<bean class="com.gupaoedu.pojo.UserBean" />
</beans>
d.测试获取
/**
* IoC的方式获取 UserBean 对象
*/
@Test
public void fun2(){
// 1.IoC容器的初始化操作 调用UserBean中无参构造器创建对象
ApplicationContext ac =
new ClassPathXmlApplicationContext("applicationContext.xml");
// 2.从容器中获取UserBean对象 没有显示的new
UserBean user = (UserBean) ac.getBean("userBean");
user.say();
}
2.2 从容器中获取对象的方式
2.2.1 根据ID
id只能声明一个
2.2.2 根据name
可以声明一个或者多个
<?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 class="com.zsc.pojo.UserBean" id="userBean" name="userBean2"/>-->
<bean class="com.zsc.pojo.UserBean" id="user1,user2,user3" name="u1,u2,u3"/>
</beans>
id="user1,user2,user3" 只表示一个
name="u1,u2,u3" 表示会被拆分为3个name属性【拆分会根据 ',' ';' ' ' 空格 】
2.2.3 根据类型
我们可以根据需要获取的对象的类型从容器中获取对象
@Test
public void fun6(){
ApplicationContext ac =
new ClassPathXmlApplicationContext("applicationContext.xml");
UserBean bean = ac.getBean(UserBean.class);
bean.say();
}
如果同一类型的对象在容器中有多个,我们仅仅只是通过类型来查找,那么就会报错
<?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 class="com.gupaoedu.pojo.UserBean" id="userBean" name="userBean2"/>-->
<bean class="com.gupaoedu.pojo.UserBean" id="user1,user2,user3" name="u1 u2 u3"/>
<bean class="com.gupaoedu.pojo.UserBean" id="userBean1" name="ub1"/>
</beans>
那么怎么解决呢?在getBean方法中通过组合条件来查找
@Test
public void fun6(){
ApplicationContext ac =
new ClassPathXmlApplicationContext("applicationContext.xml");
// UserBean bean = ac.getBean(UserBean.class);
UserBean bean = ac.getBean("u1",UserBean.class);
bean.say();
}
还要就是我们可以在<bean>中设置primary属性为true,那么当同一类型有多个对象时,就会优先返回primary属性的对象
2.3 BeanFactory和ApplicationContext的区别
/**
* ApplicationContext
* 默认在IoC容器初始化的时候就会实例化对象
*/
@Test
public void fun1(){
ApplicationContext ac =
new ClassPathXmlApplicationContext("applicationContext.xml");
}
/**
* BeanFactory
* IoC容器初始化的时候不会实例化对象
* 在调用获取的时候才会创建对象
*/
@Test
public void fun2(){
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
factory.getBean("u1");
}
类图:
从类图上我们可以很清晰的看到ApplicationContext具有BeanFactory的所有功能,同时扩展了很多BeanFactory不具备的功能(如事件广播,资源加载,web支持等等...)
2.4 工厂注入
2.4.1 静态工厂注入
<?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 class="com.zsc.factory.StaticFactoryDemo" factory-method="getInstance" id="user"></bean>
</beans>
public static Map<String,UserBean> hashMap ;
static {
hashMap = new HashMap<String, UserBean>();
hashMap.put("a1",new UserBean());
hashMap.put("a2",new UserBean());
hashMap.put("a3",new UserBean());
}
/**
* 静态工厂提供的方法
* @return
*/
public static UserBean getInstance(){
return hashMap.get("a1");
}
2.4.2 动态工厂注入
public class DynamicFactoryDemo {
public UserBean getInstance(){
return new UserBean();
}
}
?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 class="com.zsc.factory.DynamicFactoryDemo" id="dynamicFactoryDemo" ></bean>
<!-- 从工厂对象中获取 需要的对象-->
<bean id="user2" factory-bean="dynamicFactoryDemo" factory-method="getInstance"/>
</beans>
2.5 属性注入
属性注入主要是指如何给对象中的属性赋值
2.5.1 构造注入
通过构造方法注入,首先得提供对应得构造方法,既可以通过name也可以通过index来指定要赋值得参数
<?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 class="com.zsc.pojo.UserBean" id="user">
<!-- 构造注入 -->
<!--<constructor-arg name="id" value="666"/>
<constructor-arg name="userName" value="bobo"/>-->
<constructor-arg index="0" value="999" />
<constructor-arg index="1" value="gp" />
</bean>
</beans>
2.5.2 设值注入
注入的属性必须提供对应的setter方法
<bean class="com.gupaoedu.pojo.UserBean" id="user1">
<!-- 设值注入 -->
<property name="id" value="1"/>
<property name="userName" value="张三"/>
</bean>
2.5.3 其它注入类型
private Cat cat;
private String[] favorites;
private List<Cat> cats;
private Map<String,Object> map;
private Properties props;
3. 基于Java配置的实现方式
springboot流行之后,java配置的方式开始被广泛使用
java配置类
@Configuration
public class JavaConfig {
/**
* @Bean 作用和我们在applicationContext.xml中添加的<bean> 效果一样</>
* 默认的name是方法名称
* 自定义的name 可以通过value属性或者name属性来指定
* @return
*/
@Bean(name = {"aaa","bbb"})
public User getUser(){
User user = new User();
//user.set....
return user;
}
}
测试
public class MainTest1 {
@Test
public void fun1(){
// 通过@Configuraction注解来初始化IoC容器
ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
System.out.println(ac.getBean("aaa",User.class));
}
}
4.注解编程
4.1 配置注解
4.2 赋值注解
4.3 注解编程的使用
我们需要将被IOC容器管理的类型通过@Component注解标注
@Component // 需要被IoC容器加载
public class UserController {
@Autowired
private IUserService service;
public List<User> query(){
return service.query();
}
}
@Autowired和@Resource的区别
@Autowired:默认只能根据类型来查找,可以结合@Qualifier("abc")注解来实现通过name查找
@Resource:默认同样是根据类型来查找,但是提供的有type和name属性类实现不同的查找方式
4.3.1 基于java配置类的方式
我们需要在Java配置类中通过@ComponentScan注解来指定扫描的路径
默认的情况下扫描的是当前路径及其子路径下的所有被@Component @Comtroller @Service @Repository标注的类型
@Configuration
@ComponentScans({
@ComponentScan(value = {"com.zsc.controller"}
,useDefaultFilters = false
,includeFilters = {@ComponentScan.Filter(Controller.class)})
,@ComponentScan(value = {"com.zsc.service","com.zsc.dao"}
,useDefaultFilters = true
,excludeFilters = {@ComponentScan.Filter(Controller.class)})
})
public class JavaConfig {
}
4.3.2 @Value注解介绍
@value帮助我们给数组动态的设值
@Component
@Data
public class User {
@Value("bobo") // 注入普通的字符串
private String userName ;
@Value("#{systemProperties['os.name']}")
private String systemPropertiesName; // 注入操作系统的信息
@Value("#{T(java.lang.Math).random()*100}")
private double randomNumber; // 注入表达式的结果
@Value("#{person.personName}")
private String fromPersonName; // 注入其他Bean的属性
@Value("classpath:test.txt")
private Resource resourceFile;
@Value("http://www.baidu.com")
private Resource baiduFile;
}
@Component
@Data
public class Person {
@Value("PersonInfo")
private String personName;
}
java配置类
@Configuration
@ComponentScan("com.zsc")
public class JavaConfig {
}
测试
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
System.out.println(ac.getBean(User.class));
User user = ac.getBean(User.class);
}
若需要读取第三方的properties文件中的信息
创建第三方文件,在java配置类中通过@PropertySource注解来显示引入属性文件
@Configuration
@ComponentScan("com.zsc")
// 显示的指定要加载的属性文件
@PropertySource({"classpath:spring-db.properties"})
public class JavaConfig {
}
4.3.3 @PostContruct @PreDestroy @DependsOn
@PostConstruct 系统初始化完成后的回调方法
@PreDestroy 系统销毁时的回调方法
@DependsOn 指定实例化对象的先后顺序
@Component
@DependsOn({"user"}) // Person的实例化依赖于User对象的实例化,也就是User先于Person实例化
public class Person {
public Person(){
System.out.println("Person 构造方法执行了...");
}
}
4.3.4 @Import注解
将类型加入到IOC容器中的方式有哪些
1.基于XML文件的方式<bean >
2.基于XML文件的方式context:Component-Scan + @Component
3.基于Java配置类@Bean
4.基于Java配置类@ComponentScan + @Component
5.FactoryBean + getObject方法
6.@Import
4.3.4.1 静态使用
直接在@Import注解中直接定义要引入到IOC容器中的类型
缺点: 无法灵活的指定引入的类型
4.3.4.2 动态使用-ImportSelector
通过重写selectImports方法来达到灵活控制引入类型的目的
public class GpImportSelector implements ImportSelector {
/**
*
* @param annotationMetadata
* @return
* IoC 要加载的类型的全路径的字符串数组
*/
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 在此处实现不同的业务逻辑控制
return new String[]{LoggerService.class.getName(),CacheService.class.getName()};
}
}
4.3.4.3 动态使用-ImportBeanDefinitionRegistrar
public class GpImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param annotationMetadata
* @param beanDefinitionRegistry IoC容器中管理对象的一个注册器
*/
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
// 需要将添加的对象包装为一个RootBeanDefinition对象
RootBeanDefinition cache = new RootBeanDefinition(CacheService.class);
beanDefinitionRegistry.registerBeanDefinition("cache",cache);
RootBeanDefinition logger = new RootBeanDefinition(LoggerService.class);
beanDefinitionRegistry.registerBeanDefinition("logger",logger);
}
}
5.Bead对象的作用域
默认的情况是singleton
@Bean
@Scope("prototype")
public Person person(){
return new Person();
}@Bean
@Scope("prototype")
public Person person(){
return new Person();
}
@Bean
@Scope("singleton")
public Person person(){
return new Person();
}
6. 总结
本文主要介绍了SPring IOC的简单使用,Bean XML配置方式的对象获取以及DI注入,随着技术的发展,注解编程成为了时代的潮流,于是又介绍了注解结合java配置类的使用怎么更加灵活的获取对象以及属性注入的方式,最后介绍了Bean对象的作用域。对Spring的IOC有了初步的认识