bean生命周期
- 生命周期
- bean生命周期分为四个阶段:实例化、属性赋值、初始化、销毁
BeanPostProcessor接口
- 概述
- 用于在对象初始化之前、初始化之后做一些处理。
- 开发步骤
- ①自定义类实现BeanPostProcessor接口
- 重写方法
- ②编写spring-core.xml
- 将自定义类IOC到Spring容器
- ①自定义类实现BeanPostProcessor接口
- ①自定义类实现BeanPostProcessor接口
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {//在init之前执行
if (bean instanceof User) {
System.out.println("init之前");
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {//在init之后执行
if (bean instanceof User) {
System.out.println("init之后");
}
return bean;
}
}
②编写spring-core.xml
<bean class="com.atguigu.processor.MyBeanPostProcessor"></bean>
bean生命周期的练习
- 需求
- 利用bean生命周期自定义连接池
- 开发步骤
- ①自定义MyDataSource类
- ②定义MyDataSourcePostProcessor类
- ③编写spring-core.xml
- ④代码测试
- ①自定义MyDataSource类
public class MyDataSource {
public MyDataSource(){
System.out.println("①MyDataSource实例化");
}
private LinkedList<Connection> linkedList = new LinkedList<Connection>();
private String driverClassName;//驱动
public void setDriverClassName(String driverClassName) {
System.out.println("②MyDataSource属性赋值");
this.driverClassName = driverClassName;
}
private String jdbcUrl ;//数据库连接路径
private String username;//账户
private String password;//密码
private Integer initPoolSize;//初始连接数
private void loadDriver() throws ClassNotFoundException {
Class.forName(driverClassName);
}
/**
* 容器创建,init
* @throws ClassNotFoundException
* @throws SQLException
*/
public void init() throws ClassNotFoundException, SQLException {
System.out.println("③②MyDataSource init");
//加载驱动
loadDriver();
for (Integer i = 0; i < initPoolSize; i++) {
Connection connection = DriverManager.getConnection(jdbcUrl, username, password);
linkedList.add(connection);
}
}
public Connection getConnection() {
return linkedList.removeFirst();
}
public void destroy(){
System.out.println("④MyDataSource销毁");
linkedList.clear();
}
}
②定义MyDataSourcePostProcessor类
public class MyDataSourcePostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyDataSource) {
System.out.println("③①MyDataSource初始化之前");
MyDataSource dataSource = (MyDataSource) bean;
System.out.println("连接池 : " + dataSource.getInitPoolSize());//5
dataSource.setInitPoolSize(10);
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyDataSource) {
System.out.println("③③MyDataSource初始化之后");
MyDataSource dataSource = (MyDataSource) bean;
System.out.println("连接池 : " + dataSource.getInitPoolSize());//10
}
return bean;
}
}
③编写spring-core.xml
<bean id="dataSource" class="com.atguigu.datasource.MyDataSource" init-method="init" destroy-method="destroy">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mydb1"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
<property name="initPoolSize" value="5"></property>
</bean>
<bean class="com.atguigu.processor.MyDataSourcePostProcessor"></bean>
④代码测试
/**
* bean生命周期练习
*/
@Test
public void test2(){
MyDataSource dataSource = (MyDataSource) applicationContext.getBean("dataSource");
Connection connection = dataSource.getConnection();
try {
PreparedStatement statement = connection.prepareStatement("select * from tb_user");
ResultSet resultSet = statement.executeQuery();
List<User> userList = new ArrayList<User>();
while (resultSet.next()) {
User user = new User();
user.setUserName(resultSet.getString("user_name"));
userList.add(user);
}
System.out.println("userList = " + userList);
} catch (Exception e) {
e.printStackTrace();
}
applicationContext.close();
System.out.println(dataSource.getLinkedList());
}
依赖注入
- 概述
- dependency injection : 依赖注入
- 是控制反转IOC的具体体现
- 依赖注入的数据类型
- 简单类型
- javabean
- 集合
- 依赖注入的方式
- 构造器注入
- set方法注入
- 注解注入
构造器注入
- 概述
- 通过标签,使用构造器将IOC容器中的资源设置到java程序中
- 分类
- ①注入简单类型
- ②注入javabean
- 代码实现
<bean id="user" class="com.atguigu.pojo.User">
<!--注入简单类型-->
<constructor-arg name="userId" value="1"></constructor-arg>
<constructor-arg name="userName" value="zhangsan"></constructor-arg>
<constructor-arg name="userPwd" value="12345"></constructor-arg>
<!--注入javabean-->
<constructor-arg name="student" ref="student"></constructor-arg>
</bean>
<bean id="student" class="com.atguigu.pojo.Student">
<constructor-arg name="stuId" value="1"></constructor-arg>
<constructor-arg name="stuName" value="学生1"></constructor-arg>
</bean>
注意:
构造器注入跟构造器形参名有关
set注入
- 概述
- 通过标签,使用set方法将IOC容器中的资源设置到java程序中
- 代码实现
<!--set方法注入-->
<bean id="user2" class="com.atguigu.pojo.User">
<!--注入简单类型-->
<property name="userId" value="2"></property>
<property name="userName" value="lisi"></property>
<property name="userPwd" value="12345"></property>
<!--注入javabean-->
<property name="student" ref="student2"></property>
</bean>
<bean id="student2" class="com.atguigu.pojo.Student">
<constructor-arg name="stuId" value="2"></constructor-arg>
<constructor-arg name="stuName" value="学生2"></constructor-arg>
</bean>
注意:
set注入跟set方法名有关
容器注入
代码实现
public class Bean01 {
private String[] strs;
private List<String> strList;
private List<Student> studentList;
private Set<String> strSet;
private Map<Integer,String> map;
private Properties properties;
}
<!--构造器注入-->
<bean id="user" class="com.atguigu.pojo.User">
<!--注入简单类型-->
<constructor-arg name="userId" value="1"></constructor-arg>
<constructor-arg name="userName" value="zhangsan"></constructor-arg>
<constructor-arg name="userPwd" value="12345"></constructor-arg>
<!--注入javabean-->
<constructor-arg name="student" ref="student"></constructor-arg>
</bean>
<bean id="student" class="com.atguigu.pojo.Student">
<constructor-arg name="stuId" value="1"></constructor-arg>
<constructor-arg name="stuName" value="学生1"></constructor-arg>
</bean>
<!--set方法注入-->
<bean id="user2" class="com.atguigu.pojo.User">
<!--注入简单类型-->
<property name="userId" value="2"></property>
<property name="userName" value="lisi"></property>
<property name="userPwd" value="12345"></property>
<!--注入javabean-->
<property name="student" ref="student2"></property>
</bean>
<bean id="student2" class="com.atguigu.pojo.Student">
<constructor-arg name="stuId" value="2"></constructor-arg>
<constructor-arg name="stuName" value="学生2"></constructor-arg>
</bean>
<!--容器注入-->
<bean id="bean01" class="com.atguigu.pojo.Bean01">
<property name="strs">
<array>
<value>a</value>
<value>b</value>
<value>c</value>
</array>
</property>
<property name="strList">
<list>
<value>a</value>
<value>b</value>
<value>c</value>
</list>
</property>
<property name="studentList">
<list>
<bean id="myStu1" class="com.atguigu.pojo.Student"></bean>
<bean id="myStu2" class="com.atguigu.pojo.Student"></bean>
<ref bean="student"></ref>
<ref bean="student2"></ref>
</list>
</property>
<property name="strSet">
<set>
<value>a</value>
<value>b</value>
<value>c</value>
</set>
</property>
<property name="map">
<map>
<entry key="1" value="a"></entry>
<entry key="2" value="b"></entry>
<entry key="3" value="c"></entry>
</map>
</property>
<property name="properties">
<props>
<prop key="1">a</prop>
<prop key="2">b</prop>
<prop key="3">c</prop>
</props>
</property>
</bean>
p命名空间
- 概述
- 为了简化依赖注入操作。
- 语法
<bean
p:propertyName="值"
p:propertyName-ref="beanId"></bean>
代码实现
<bean id="user3"
class="com.atguigu.pojo.User"
p:userId="3"
p:userName="阿磊"
p:userPwd="250"
p:student-ref="student3">
</bean>
<bean id="student3"
class="com.atguigu.pojo.Student"
p:stuId="31"
p:stuName="阿三">
</bean>
ApplicationContext的结构- 层次结构
- 层次结构
BeanFactory和ApplicationContext的区别
- BeanFactory
- 提供最基础的IOC功能
- 使用bean时才初始化
- ApplicationContext
- 除了有最基础的IOC功能以外,还有AOP、事务管理、JDBCTemplate…
- 容器初始化bean就初始化
- 代码实现
public class ApplicationContextTest {
@Test
public void test1(){
//ApplicationContext : IOC容器初始化,bean就初始化
//ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-core.xml");
//BeanFactory : IOC容器初始化,bean不初始化,在使用bean时才初始化
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-core.xml"));
beanFactory.getBean("user");
}
}
ApplicationContext的三个实现类
- ClassPathXmlApplicationContext
- 根据类路径下的xml配置文件加载Spring容器
- FileSystemXmlApplicationContext
- 根据系统磁盘路径下的xml配置文件加载Spring容器
- AnnotationConfigApplicationContext
- 在纯注解开发中,根据配置类加载Spring容器
- 代码实现
@Test
public void test2(){
ApplicationContext applicationContext = new FileSystemXmlApplicationContext("C:\\Users\\qiuzhiwei\\Desktop\\spring-core.xml");
Object user = applicationContext.getBean("user");
System.out.println("user = " + user);
}
Spring操作数据库
- 需求
- Spring 整合 DbUtils,查询用户列表
- 开发步骤
- ①引入相关依赖
- ②编写UserController
- ③定义UserService及其实现子类
- ④定义UserDao及其实现子类
- ⑤编写spring-core.xml
- ①引入相关依赖
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<junit.version>4.13.2</junit.version>
<lombok.version>1.18.22</lombok.version>
<spring.version>5.3.13</spring.version>
<dbutils.version>1.7</dbutils.version>
<druid.version>1.2.8</druid.version>
<mysql.version>5.1.48</mysql.version>
</properties>
<dependencies>
<!--junit start-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!--junit end-->
<!--lombok start-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!--lombok end-->
<!--spring start-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<!--spring end-->
<!--jdbc start-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>${dbutils.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--jdbc end-->
</dependencies>
②编写UserController
public class UserController {
public static void main(String[] args) throws Exception {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-core.xml");
UserService userService = applicationContext.getBean(UserService.class);
List<User> userList = userService.selectUserList();
System.out.println("userList = " + userList);
}
}
③定义UserService及其实现子类
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public List<User> selectUserList() throws Exception {
return userDao.selectUserList();
}
}
④定义UserDao及其实现子类
public class UserDaoImpl implements UserDao {
private QueryRunner queryRunner;
public void setQueryRunner(QueryRunner queryRunner) {
this.queryRunner = queryRunner;
}
@Override
public List<User> selectUserList() throws Exception {
return queryRunner.query(
"select user_id userId,user_name userName, user_pwd userPwd from tb_user",
new BeanListHandler<>(User.class)
);
}
}
⑤编写spring-core.xml
<!--5.1,将UserServiceImpl对象放入到Spring容器,userDao成员变量进行注入-->
<bean id="userService" class="com.atguigu.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<!--5.2,将UserDaoImpl对象放入到Spring容器,queryRunner成员变量进行注入-->
<bean id="userDao" class="com.atguigu.dao.impl.UserDaoImpl">
<property name="queryRunner" ref="queryRunner"></property>
</bean>
<!--5.3,将QueryRunner对象放入到Spring容器,ds成员变量进行注入-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="dataSource"></constructor-arg>
</bean>
<!--5.4,将DruidDataSource对象放入到Spring容器,四个成员变量driverClassName、url、username、password进行注入-->
<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/mydb1"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
SpringIOC注解
说明
- 学习基于注解的 IoC 配置,大家脑海里首先得有一个认知,即注解配置和 xml 配置要实现 的功能都是一样 的,都是要降低程序间的耦合。只是配置的形式不一样。
- 关于实际的开发中到底使用xml还是注解,每家公司有着不同的使用习惯。所以这两种配置 方式我们都需要掌 握。
注解创建对象
- 开发步骤
- ①扫描注解
- ②使用@Controller、@Service、@Repository、@Component
- ③代码测试
- ①扫描注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--扫描注解-->
<context:component-scan base-package="com.atguigu"></context:component-scan>
</beans>
②使用@Controller、@Service、@Repository、@Component
@Controller("userController")
public class UserController {
public void selectUserList(){
System.out.println("UserController selectUserList");
}
}
@Service("userService")
public class UserServiceImpl implements UserService {
@Override
public void selectUserList() throws Exception {
System.out.println("UserServiceImpl selectUserList");
}
}
@Repository("userDao")
public class UserDaompl implements UserDao {
@Override
public void selectUserList() throws Exception {
System.out.println("UserDaompl selectUserList");
}
}
@Component("user")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer userId;
private String userName;
private String userPwd;
}
③代码测试
public class AnnotationTest {
private ApplicationContext applicationContext ;
@Before
public void init(){
applicationContext = new ClassPathXmlApplicationContext("spring-core.xml");
}
@Test
public void test1() throws Exception {
UserController userController = (UserController) applicationContext.getBean("userController");
userController.selectUserList();
UserService userService = (UserService) applicationContext.getBean("userService");
userService.selectUserList();
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.selectUserList();
User user = (User) applicationContext.getBean("user");
System.out.println("user = " + user);
}
}
**- 注意事项
- @Controller、@Service、@Repository就是@Component
**
扫描详解
- 方式
- ①基本扫描
- ②排除扫描
- 排除@Controller
- ③包含扫描
- 只扫描@Controller
- ①基本扫描
<context:component-scan base-package="com.atguigu"></context:component-scan>
②排除扫描
<context:component-scan base-package="com.atguigu">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
③包含扫描
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
**- 适用场景
- 聚合项目中不同模块负责扫描不同的注解。
**
依赖注入之@Autowired
- 概述
- 相当于:
- 先按照类型进行注入,再按照beanid进行注入
- 工作流程
- 代码实现
@Controller("userController")
public class UserController {
@Autowired
private UserService userService2;
public void selectUserList() throws Exception {
System.out.println("UserController selectUserList");
userService2.selectUserList();
}
}
@Service("userService1")
public class UserServiceImpl implements UserService {
@Override
public void selectUserList() throws Exception {
System.out.println("UserServiceImpl selectUserList");
}
}
@Service("userService2")
public class UserServiceImpl2 implements UserService {
@Override
public void selectUserList() throws Exception {
System.out.println("UserServiceImpl2 selectUserList");
}
}
**- 注意事项
- @Autowired不需要set方法
**
依赖注入之@Qualifier
- 概述
- 配合@Autowired适用,按照beanid进行注入
- 代码实现
@Controller("userController")
public class UserController {
@Autowired
@Qualifier("userService2")
private UserService userService;
public void selectUserList() throws Exception {
System.out.println("UserController selectUserList");
userService.selectUserList();
}
public void selectUserList2() throws Exception {
System.out.println("UserController selectUserList");
userService.selectUserList();
}
}
@Autowired的其他细节
- 概述
- @Autowired不仅仅可以作用在成员变量,也可以作用在构造器、set方法等
- ①标记在构造器
@Component
public class UserServiceWrapper {
private UserService userService;
@Autowired
public UserServiceWrapper(UserService userService2) {
this.userService = userService1;
}
public UserService getUserService() {
return userService;
}
}
②标记在set方法
@Component
public class UserServiceWrapper {
private UserService userService;
@Autowired//将Spring容器中的UserService类型的bean注入到形参userService上
@Qualifier("userService2")
public void setUserService(UserService userService){
this.userService = userService;
}
public UserService getUserService() {
return userService;
}
}
③佛系装配 : 一般情况下,如果装配失败抛出异常,设置佛系后,装配失败就拉到!!
@Controller("userController")
public class UserController {
@Autowired(required = false)//佛系装配
@Qualifier("userService3")
private UserService userService = null;
public void selectUserList() throws Exception {
System.out.println("UserController selectUserList");
userService.selectUserList();
}
}
依赖注入之@Resource
- 概述
- 相当于:
- JSR-250提供的,它是Java标准,绝大部分框架都支持。
- 代码实现
@Controller("userController")
public class UserController {
//①同时指定了name和type,查找name和type唯一匹配的bean
//@Resource(name = "userService2",type = UserServiceImpl2.class)
//②指定name,查找name唯一匹配的bean
//@Resource(name = "userService2")
//③指定type,查找type唯一匹配的bean
//@Resource(type = UserServiceImpl2.class)
//④既没有指定name,也没有指定type。先按照name查找,再按照type查找
@Resource
private UserServiceImpl userService;
public void selectUserList() throws Exception {
System.out.println("UserController selectUserList");
userService.selectUserList();
}
}
依赖注入之@Value
- 概述
- 给简单类型注入值
- 读取properties配置文件中的值并注入
- 代码实现
@Component("user")
public class User {
@Value("1")
private Integer userId ;
@Value("浩浩")
private String userName;
@Value("haohao")
private String userPwd;
}
注解整合junit
代码实现
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-core.xml")
public class UserServiceTest {
private ApplicationContext applicationContext ;
@Autowired
@Qualifier("userService2")
private UserService userService;
@Test
public void test1() throws Exception {
userService.selectUserList();
}
}