1、IOC操作Bean管理(FactoryBean)
1.Spring有两种类型bean,一种普通bean,另外一种工厂bean(FactoryBean)
2.普通bean: 在配置文件中定义bean类型就是返回类型
3.工厂bean: 在配置文件定义bean类型可以和返回类型不一样
第一步 创建类,让这个类作为工厂bean,实现接口FactoryBean
第二步 实现接口里面的方法,在实现的方法中定义返回的bean 类型
public class MyBean implements FactoryBean<Course> {
//定义返回bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("abc");
return course;
}
}
<bean id="myBean" class="com.atguigu.spring5.factorybean.MyBean">
</bean>
@Test
public void test3() {
ApplicationContext context =
new ClassPathXmlApplicationContext("bean3.xml");
Course course = context.getBean("myBean", Course.class);//返回值类型可以不是定义的bean类型!
System.out.println(course);
}
2、Bean的作用域
1.在Spring里面,设置创建bean实例是单实例还是多实例
2.在spring里面,默认情况下,bean是单实例对象
3.如何设置单实例还是多实例
(1)在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例
(2)scope属性值:
第一个值 默认值,singleton,表示单实例对象
第二个值 prototype,表示是多实例对象
(3)singleton和prototype区别
第一 singleton单实例,prototype多实例
第二 设置scope值是singleton的时候,加载spring配置文件时候就会创建单实例对象
设置scope值是prototype的时候,不是在加载spring配置文件时候创建对象,在调用getBean方法时候创建多实例对象
详细介绍: https://blog.csdn.net/qq_45632660/article/details/110093592
3、Bean的生命周期
1.生命周期
(1)从对象创建到对象销毁的过程
2.bean生命周期
(1)通过构造器创建bean示例(无参数构造器)
(2)为bean的属性设置值和对其他bean引用(调用set方法)
(3)调用bean的初始化的方法(需要进行配置初始化的方法)
(4)bean可以使用了(对象获取到了)
(5)当容器关闭时候,调用bean 的销毁的方法(需要进行配置销毁的方法)
3.演示生命周期
public class Orders {
//无参数构造
public Orders() {
System.out.println("第一步 执行无参数构造创建 bean 实例");
}
private String oname;
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步 调用 set 方法设置属性值");
}
//创建执行的初始化的方法
public void initMethod() {
System.out.println("第三步 执行初始化的方法");
}
//创建执行的销毁的方法
public void destroyMethod() {
System.out.println("第五步 执行销毁的方法");
}
}
public class MyBeanPost implements BeanPostProcessor {//创建后置处理器实现类
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行的方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行的方法");
return bean;
}
}
<!--配置文件的bean参数配置-->
<bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod"> <!--配置初始化方法和销毁方法-->
<property name="oname" value="手机"></property><!--这里就是通过set方式(注入属性)赋值-->
</bean>
<!--配置后置处理器-->
<bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>
@Test
public void testBean3() {
// ApplicationContext context =
// new ClassPathXmlApplicationContext("bean4.xml");
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean4.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四步 获取创建 bean 实例对象");
System.out.println(orders);
//手动让 bean 实例销毁
context.close();
}
4、bean 的后置处理器,bean 生命周期有七步 (正常生命周期为五步,而配置后置处理器后为七步)
(1)通过构造器创建 bean 实例(无参数构造)
(2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
(3)把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
(4)调用 bean 的初始化的方法(需要进行配置初始化的方法)
(5)把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
(6)bean 可以使用了(对象获取到了)
(7)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
4、自动装配
4.1、什么是自动装配
根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
4.2、autowire
byName
(1) 根据属性名称自动注入
演示
//Dept
public class Dept {
@Override
public String toString() {
return "Dept{}";
}
}
//Emp
public class Emp {
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"dept=" + dept +
'}';
}
public void test(){
System.out.println(dept);
}
}
//bean.xml
<!--实现自动装配
bean标签属性autowire,配置自动装配
autowire属性常用有两个值:
byName根据属性名称注入,注入值bean的id值和类属性名称一样
byType根据属性类型注入
-->
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName">
</bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
当一个bean节点带有 autowire byName的属性时。
- 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。
- 去spring容器中寻找是否有此字符串名称id的对象。
- 如果有,就取出注入;如果没有,就报空指针异常。
相当于使用外部bean
byType
(2) 根据属性类型注入
演示
<!--实现自动装配
bean标签属性autowire,配置自动装配
autowire属性常用有两个值:
byName根据属性名称注入,注入值bean的id值和类属性名称一样
byType根据属性类型注入
-->
<bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byType">
</bean>
<bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。
推荐不使用自动装配xml配置 , 而使用注解 .
5、外部属性
方式一: 直接配置数据库信息 (1)配置Druid连接池 (2)引入Druid连接池依赖jar包
<!--直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
方式二: 引入外部属性文件配置数据库连接池
(1)创建外部属性文件,properties格式文件,写数据库信息
driverClass="com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/userDb
userName=root
password=root
(2)把外部properties属性文件引入到spring配置文件中
- 引入context名称空间
<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:property-placeholder location="jdbc.properties"/>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driverClass}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${userName}"></property>
<property name="password" value="${password}"></property>
</bean>
6、注解
6.1、什么是注解
- 注解是代码特殊标记,格式:
@注解名称(属性名称=属性值,属性名称=属性值...)
- 注解可以使用在类上面,方法上面,属性上面。
- 使用注解目的: 简化xml配置
6.2、Bean管理中创建对象提供注解
- @Component
- @Service
- @Controller
- @Repository
上面四个注解功能是一样的,都可以用来创建bean实例
@Service(value = "userService")
相当于
<bean id="userService" class="com.atguigu.spring5.service"></bean>
在注解里面value属性值可以省略不写,默认值是类名称,首字母小写
6.2.1、基于注解方式实现对象创建
第一步 引入依赖
第二步 开启组件扫描,扫描注解,不扫描就不能使用注解。
<!--开启组件扫描
1 如果扫描多个包,多个包使用逗号隔开
2 扫描包上层目录
-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
第三步 创建类,在类上面添加创建对象注解
@Service(value = "userService")
public class userService {
public void add(){
System.out.println("service add");
}
}
6.2.2、开启组件扫描细节配置
<!--示例1
use-default-filters="false" 表示现在不使用默认filter,自己配置filter
如果不配置use-default-filters="false"代表要全部扫描,配置了就代表不扫描,需要自己手动配置扫描
context:include-filter 设置扫描哪些内容
下面组件的意思是: 扫描com.atguigu包下Controller的注解
-->
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--示例 2
下面配置扫描包所有内容
context:exclude-filter: 设置哪些内容不进行扫描
-->
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/><!--表示Controller注解的类之外一切都进行扫描-->
</context:component-scan>
6.2.3、基于注解方式实现属性注入
Autowired : 根据属性类型进行自动注入
第一步 把service和dao对象创建,在service和dao类添加创建对象注解
第二步 在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解
@Service
public class UserService {
//定义 dao 类型属性
//不需要添加 set 方法
//添加注入属性注解
@Autowired
private UserDao userDao;
public void add() {
System.out.println("service add.......");
userDao.add();
}
}
//Dao实现类
@Repository
//@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("dao add.....");
}
}
Qualifier: 根据属性名称进行注入,不能单独使用,和Autowired一起使用。
//定义 dao 类型属性
//不需要添加 set 方法
//添加注入属性注解
@Autowired //根据类型进行注入
//根据名称进行注入(目的在于区别同一接口下有多个实现类,根据类型就无法选择,从而出错!)
@Qualifier(value = "userDaoImpl")
private UserDao userDao;
Resource: 可以根据类型注入,也可以根据属性名称注入。它属于javax包下的注解,不推荐使用!)
- @Resource如有指定的name属性,先按该属性进行byName方式查找装配;
- 其次再进行默认的byName方式进行装配;
- 如果以上都不成功,则按byType的方式自动装配。
- 都不成功,则报异常。
//@Resource //根据类型进行注入
@Resource(name = "userDaoImpl1") //根据名称进行注入
private UserDao userDao;
Value: 注入普通类型属性
@Value(value = "abc")
private String name
6.3、@Configuration 完全注解开发
(1)创建配置类,替代 xml 配置文件
@Configuration //作为配置类,替代 xml 配置文件
@ComponentScan(basePackages = {"com.atguigu"})
public class SpringConfig {
}
(2)编写测试类
@Test
public void testService2() {
//加载配置类
ApplicationContext context
= new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService",
UserService.class);
System.out.println(userService);
userService.add();
}