1.spring创建对象的范围
1.1关于单例和多例的介绍
单例: 内存中只有一个对象,每次获取到该对象的地址值一样.
多例:内存中的每个对象都是一个新的对象,他们的地址值都不同.
spring默认的情况下创建的对象都是单例的. (每次返回的对象都是同一个)
默认scope=singleton
1.1.1单例代码结果演示
代码
<!--2,通过无参构造创建对象-->
<bean id="user01" class="com.sen.ioc.Demo02_User" ></bean>
结果
1.1.2多例代码结果演示
代码
<!--2,通过无参构造创建对象-->
<bean id="user01" class="com.sen.ioc.Demo02_User" scope="prototype" ></bean>
结果
1.3spring创建对象的生命周期
spring创建的对象什么时候创建
回答:配置文件读取加载的时候对象就创建(scope=“singleton”)
spring读取xml文件的时候,不会创建对象
在调用容器的getBean(“id”) 得到对象(scope=“prototype”)
spring创建的对象什么时候运行
回答:当使用该对象的时候就运行
spring创建的对象什么时候销毁
回答:当spring的容器关闭的时候对象销毁
!!注意
//对Spring的生命周期进行测试
@Test
public void test05(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
"applicationContext.xml"
);
Student student = context.getBean("student", Student.class);
student.service();
//猜测结果,init方法应该这service方法执行前执行
context.close();
//这里不报错,因为student2还存在堆内存
student2.service();
//这里报错,因为spring容器已经销毁
Student student1 = context.getBean("student", Student.class);
//猜测destroy方法应该在这句话执行后结束并且service不会再执行
student3.service();
}
二.依赖注入
1.概念
DI (dependency injection) 依赖注入
含义:就是给对象的属性设置值.
原来给对象的属性设置值: set方法给对象设置值 构造方法给对象初始化的时候设置值.
1.1set方式设置属性
注意点:
- set注入 ,必须要有set方法
- personbean.xml
这里不写的属性为0/Null
<?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="birthday" class="java.util.Date"></bean>
<!--创建对象-->
<bean id="person" class="com.itheima.di.Person">
<!--
name : 代表的是set方法去掉set首字母变小写的值;
value : 给该属性设置的值(基本类型或string)
ref : 给该对象属性设置值,ref中写的是对象的id
-->
<property name="id" value="1" ></property>
<property name="userName" value="志平" ></property>
<property name="age" value="38" ></property>
<property name="birthday" ref="birthday"></property>
</bean>
</beans>
- 测试
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class PersonTest {
/*
1.创建对象给对象设置属性,打印的对象是有属性的,属性是在xml中设置的.
2.执行过程中会调用set方法,打断点查看流程
3.是否根据set方法来设置的: 修改set方法
*/
@Test
public void testPerson(){
ApplicationContext context =
new ClassPathXmlApplicationContext("personbean.xml");
Person person = context.getBean("person", Person.class);
System.out.println(person);
}
}
1.2构造方式注入
- 前提条件类中必须有有参构造方法
- personbean.xml
这里必须写全有参构造中出现的属性,不然报编译时错误
<!--采用构造方法创建对象-->
<bean id="person02" class="com.itheima.di.Person">
<!--
constructor-arg 构造方法注入
name 代表的构造方法上的属性名称
value 代表传递的属性值(基本+String)
ref 注入的是引用类型
-->
<constructor-arg name="name" value="小龙女" ></constructor-arg>
<constructor-arg name="id" value="2" ></constructor-arg>
<constructor-arg name="age" value="18" ></constructor-arg>
<constructor-arg name="birthday" ref="birthday"></constructor-arg>
</bean>
1.3p名称空间注入和c名称空间注入
-
P代表propertory 属性, 是set注入的简化方式 (提供set方法)
-
C代表Constructor 构造注入的简化方式 (提供构造方法)
-
配置文件
先引入
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
这里的c -Constructor 构造注入的简化方式属性必须全写,不然报运行时错误
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
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="birthday" class="java.util.Date"></bean>
<!--使用p名称空间注入属性-->
<bean id="person_p" class="com.itheima.di.Person" p:id="3" p:userName="杨过" p:age="22" p:birthday-ref="birthday"/>
<!--使用c名称空间注入-->
<bean id="person_c" class="com.itheima.di.Person" c:id="3" c:name="雕" c:age="220" c:birthday-ref="birthday"/>
</beans>
科普
①编译错误一般指语法错误或者很明显的逻辑错误。
如:缺少分号,少写括号,关键字书写错误等, 在eclipse往往会画红线。
②运行错误是在没有编译错误的基础上运行后产生的逻辑错误。
如:空指针异常,除数为0,越界访问等,一般会抛出异常。
1.4复杂数据类型注入
类中属性Aarry 数组 List 集合 Map集合 Set集合 Properties集合属性设置值.
- ComplexBean
import java.util.*;
/**
* 采用的是set方式注入
*/
public class ComplexBean {
private String[] arr;
private List<Person> list;
private Set<String> set;
private Map<String,Person> map;
private Properties properties;
public String[] getArr() {
return arr;
}
public void setArr(String[] arr) {
this.arr = arr;
}
public List<Person> getList() {
return list;
}
public void setList(List<Person> list) {
this.list = list;
}
public Set<String> getSet() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
public Map<String, Person> getMap() {
return map;
}
public void setMap(Map<String, Person> map) {
this.map = map;
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public String toString() {
return "ComplexBean{" +
"arr=" + Arrays.toString(arr) +
", list=" + list +
", set=" + set +
", map=" + map +
", properties=" + properties +
'}';
}
}
- 配置文件
<!--注入复杂数据类型-->
<bean id="complexBean" class="com.itheima.di.ComplexBean">
<!--1.先注入数组-->
<property name="arr">
<array>
<value>柯镇恶</value>
<value>郭靖</value>
<value>杨过</value>
</array>
</property>
<!--2.注入list类型-->
<property name="list">
<list>
<ref bean="person" />
<ref bean="person02" />
<ref bean="person_p" />
</list>
</property>
<!--3.注入set集合-->
<property name="set">
<set>
<value>乔峰</value>
<value>段誉</value>
<value>虚竹</value>
</set>
</property>
<!--4.注入map-->
<property name="map">
<map>
<entry key="志平" value-ref="person"/>
<entry key="小龙女" value-ref="person02"/>
<entry key="杨过" value-ref="person_p"/>
</map>
</property>
<!--5.注入properties-->
<property name="properties">
<props>
<prop key="no1">石破天</prop>
<prop key="no2">虚竹</prop>
<prop key="no3">张无忌</prop>
</props>
</property>
</bean>
- 测试
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.*;
public class ComplexBeanTest {
@Test
public void testComplexBean(){
ApplicationContext context =
new ClassPathXmlApplicationContext("personbean.xml");
ComplexBean complexBean = context.getBean("complexBean", ComplexBean.class);
String[] arr = complexBean.getArr();
System.out.println(Arrays.toString(arr));
System.out.println("---------------------");
List<Person> list = complexBean.getList();
for (Person person : list) {
System.out.println(person);
}
System.out.println("---------------------");
Set<String> set = complexBean.getSet();
System.out.println(set);
System.out.println("---------------------");
Map<String, Person> map = complexBean.getMap();
Set<Map.Entry<String, Person>> entrySet = map.entrySet();
for (Map.Entry<String, Person> entry : entrySet) {
System.out.println(entry.getKey()+ " "+ entry.getValue());
}
System.out.println("---------------------");
Properties properties = complexBean.getProperties();
System.out.println(properties);
}
}
三.注解方式的IOC和DI
1.使用注解方式创建对象
1.需要导入一个aop.jar的jar ,该包已经被spring-context.jar依赖引入了.不需要再导入(Idea)
2.在配置文件中需要进行一个包扫描的配置
2.代码实现
- annotationbean.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">
<!--使用注解扫描包,创建对象
该注解可以扫描我们配置的包下的所有的类.
扫描这些类上有没有添加指定的注解, 如果有指定的注解,就会创建对象
-->
<context:component-scan base-package="com.sen.annotation" ></context:component-scan>
</beans>
- UserService接口
public interface UserService {
//查询用户
public void findUsers();
}
- UserServiceImpl
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
//@Component注解 ===> <bean id="userServiceImpl" class="xxxx">
// @Component 默认的id是类名首字母小写
//@Component("abc") //手动的指定了 <bean id="abc" class="xxxx">
/**
* 和Component注解作用一样的还有其他3个:
* 这4个注解的作用一样
*/
//@Component //不确定是那一层使用Component
//@Controller //确定是表现层/控制层 使用Controller
@Service //如果是业务逻辑使用 Service
//@Repository // 如果是dao持久层 Repository
public class UserServiceImpl implements UserService {
public void findUsers() {
System.out.println("用户查询完毕");
}
}
2.使用注解方式注入
- UserDao接口
public interface UserDao {
public void queryUsers();
}
- UserDaoImpl
@Repository("son1")
public class UserDaoImpl implements UserDao {
public void queryUsers() {
System.out.println("1111 dao的查询user方法");
}
}
- UserDaoImpl02
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
//@Component注解 ===> <bean id="userServiceImpl" class="xxxx">
// @Component 默认的id是类名首字母小写
//@Component("abc") //手动的指定了 <bean id="abc" class="xxxx">
/**
* 和Component注解作用一样的还有其他3个:
* 这4个注解的作用一样
*/
//@Component //不确定是那一层使用Component
//@Controller //确定是表现层/控制层 使用Controller
@Service //如果是业务逻辑使用 Service
//@Repository // 如果是dao持久层 Repository
public class UserServiceImpl implements UserService {
//使用自动注入的注解,将userDao的实现类UserDaoImpl注入进来
//byType按照类型注入 ,问题如果UserDao中有多个实现类,注入的是哪个? 会报错
@Autowired
@Qualifier("son2") //根据的bean id值来指定
private UserDao userDao;
public void findUsers() {
System.out.println("Service用户查询完毕");
//创建dao的对象并调用dao的query方法
userDao.queryUsers();
}
}
- 测试
public class UserServiceTest {
@Test
public void testUserService(){
ApplicationContext context =
new ClassPathXmlApplicationContext("annotationbean.xml");
UserServiceImpl userServiceImpl = context.getBean("userServiceImpl", UserServiceImpl.class);
userServiceImpl.findUsers();
}
}
3.其他的注入方式
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.annotation.Resources;
@Service //如果是业务逻辑使用 Service
public class UserServiceImpl implements UserService {
//方式2注入:
//@Value("#{son1}") //将UserDaoImpl02注入进来
//private UserDao userDao;
@Value("志平")
private String name;
//注入方式3:jdk的注入
@Resource(name="son1")
private UserDao userDao;
public void findUsers() {
System.out.println("Service用户查询完毕" +name);
//创建dao的对象并调用dao的query方法
userDao.queryUsers();
}
}