文章目录
必须提前知道的概念
控制反转IOC
建议阅读下面这篇文章之后在看这篇文章
点此进入IOC的文章
IOC里面的Bean
什么是Bean管理
- Bean 管理指的是两个操作
- Spring 创建对象
- Spirng 注入属性
Bean管理操作的两种形式
- 基于xml配置文件的实现
- 基于注解方式的实现
在本篇文章中我们来讲述基于xml配置文件的实现
面向切面Aop
面向切面,不修改源代码进行功能增强
关于AOP的话就不在这里细嗦了 细嗦的话篇幅有点太长了 等以后有时间会专门写的
Aop的文章1
Aop的文章2
狂神说AOP
使用spring的maven配置文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>spring_study</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring.version>4.3.7.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<!--开源日志组件 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<!-- spring基本框架核心工具类,其他spring组件都需要依赖这个包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<!--包含配置文件,创建和管理bean -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
</dependencies>
</project>
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" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
</beans>
我们通过配置bean来把我们要用的代码给注册到spring容器之中
第一个spring程序
编写第一个spring的Java代码
package com.tong.pojo;
public class hello {
public void hello() {
System.out.println("helloworld this is my first spring");
}
}
配置xml文件
<!--bean就是java对象 , 由Spring创建和管理-->
<bean id="hello" class="com.tong.pojo.hello">
</bean>
测试
@Test
public void my_first_spring() {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
com.tong.pojo.hello hello = (com.tong.pojo.hello) classPathXmlApplicationContext.getBean("hello");
com.tong.pojo.hello hello1 = classPathXmlApplicationContext.getBean("hello", com.tong.pojo.hello.class);
hello.hello();
hello1.hello();
}
测试结果
我们通过
ClassPathXmlApplicationContext cl = new ClassPathXmlApplicationContext("beans.xml");
来读取配置文件
通过
com.tong.pojo.hello hello1 = cl.getBean("hello", com.tong.pojo.hello.class);
hello.hello();
来获取配置文件里面注册的bean对应的对象
基于xml注入属性
通过set方法注入
创建工具类
package com.tong.pojo;
public class add_to_by_set {
private String add_String;
public void setAdd_String(String add_String) {
this.add_String = add_String;
}
public String getAdd_String() {
return add_String;
}
}
我们往这玩意里面注入
配置xml
<!-- 通过set方法注入-->
<bean id="add_set" class="com.tong.pojo.add_to_by_set">
<property name="add_String" value="这是通过set注入的string"/>
</bean>
划重点
- bean里面的id是提供给Java代码里面的getBean使用的
- class是指定使用的是那个具体的java类
- proerty的name指的是注入到那个set方法里面
- proerty的value是注入的数值
测试
@Test
public void add_by_set() {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
add_to_by_set add_set = classPathXmlApplicationContext.getBean("add_set", add_to_by_set.class);
String add_string = add_set.getAdd_String();
System.out.println(add_string);
}
通过构造器注入
工具类
package com.tong.pojo;
public class add_by_constructor {
private String string;
private int num;
public String getString() {
return string;
}
public int getNum() {
return num;
}
@Override
public String toString() {
return "add_by_constructor{" +
"string='" + string + '\'' +
", num=" + num +
'}';
}
public add_by_constructor(String string, int num) {
this.string = string;
this.num = num;
}
}
xml配置文件
<bean id="add_constructor" class="com.tong.pojo.add_by_constructor">
<constructor-arg name="string" value="这是构造器注入的string"/>
<constructor-arg name="num" value="11"/>
</bean>
划重点
- bean里面的constructor-arg 来表示构造器注入
- property 是set方法注入
注入类属性为其他类型
假如说现在有两个类 员工(staff) 和部门(department)
一个员工对应一个部门
也就是说员工里面需要一个部门属性
我们来实现一个这个的注入
工具类
员工类
package one_to_many;
public class Staff {
private String staffName;
private int staffAge;
private Department department;
public void setStaffName(String staffName) {
this.staffName = staffName;
}
public void setStaffAge(int staffAge) {
this.staffAge = staffAge;
}
public void setDepartment(Department department) {
this.department = department;
}
@Override
public String toString() {
return "Staff{" +
"staffName='" + staffName + '\'' +
", staffAge=" + staffAge +
", department=" + department +
'}';
}
}
部门类
package one_to_many;
public class Department {
private String departmentId;
private String departmentName;
public String getDepartmentId() {
return departmentId;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentId(String departmentId) {
this.departmentId = departmentId;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
@Override
public String toString() {
return "Department{" +
"departmentId='" + departmentId + '\'' +
", departmentName='" + departmentName + '\'' +
'}';
}
}
xml配置文件
我们先配置部门
<!-- 职员的部门-->
<bean id="department" class="one_to_many.Department">
<property name="departmentId" value="123">
</property>
<property name="departmentName" value="人力"/>
</bean>
我们将部门给引入到职员类里面
<bean id="staff" class="one_to_many.Staff">
<property name="department" ref="department"/>
<property name="staffAge" value="12"/>
<property name="staffName" value="nana"/>
</bean>
划重点
bean里面的property是表示set方法的注入上面我们已经嗦过了注入的如果是引用的话就用ref ref里面的实际上就是bean里面配置的id
测试
@Test
public void one_to_many() {
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
Staff test2 = classPathXmlApplicationContext.getBean("staff", Staff.class);
String s = test2.toString();
System.out.println(s);
}
注入数值 集合 map
注入就是这么个注入方式
<bean id="collection" class="com.test.CollectionArray">
<!--数组-->
<property name="strings">
<list>
<value>array1</value>
<value>array2</value>
</list>
</property>
<!--list 集合-->
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
</list>
</property>
<!--map 集合-->
<property name="map">
<map>
<entry key="map1" value="map1"/>
<entry key="map2" value="map2"/>
</map>
</property>
<!--set 集合-->
<property name="set">
<list>
<value>set1</value>
<value>set2</value>
</list>
</property>
</bean>
下面是具体举例
List注入
工具类
package array_map_conllection;
import java.util.List;
public class Book {
private List<String> bookName;
public void setBookName(List<String> bookName) {
this.bookName = bookName;
}
@Override
public String toString() {
return "Book{" +
"bookName=" + bookName +
'}';
}
}
xml配置
<!-- 抽取公共部分-->
<bean id="book" class="array_map_conllection.Book">
<property name="bookName" ref="bookList"/>
</bean>
<util:list id="bookList">
<value>book1</value>
<value>book2</value>
</util:list>
测试
@Test
public void test1(){
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
Book book = classPathXmlApplicationContext.getBean("book", Book.class);
String s = book.toString();
System.out.println(s);
}
工厂Bean
Spring 有两种类型 bean,一种普通 bean,另外一种工厂
bean(FactoryBean)
- 普通 bean:在配置文件中定义 bean 类型就是返回类型
- 工厂 bean:在配置文件定义 bean 类型可以和返回类型
不一样
怎么搞一个自己的工厂bean
- 创建类,让这个类作为工厂 bean,实现接口
FactoryBean - 实现接口里面的方法,在实现的方法中定义返回的
bean 类型
package Bean;
import array_map_conllection.Person;
import org.springframework.beans.factory.FactoryBean;
public class MyFactoryBean implements FactoryBean<Person> {
@Override
public Person getObject() throws Exception {
return new Person();
//这里我们就整了一个一个自定义的返回对象
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
这是用到的一个简单的person类
package array_map_conllection;
public class Person {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Persion{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
在配置一哈xml文件
<bean id="myPostProcessor" class="Bean.MyPostProcessor"/>
测试
@Test
public void myFactory(){
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
Person person = classPathXmlApplicationContext.getBean("myFactory", Person.class);
System.out.println(person);
}
Bean的作用域
使用 xml 创建 bean 的时候默认是单例模式,只能创建一个对
象
如果想创建多个对象需要在 Bean 标签中加入 scope 属性值
为 prototype
Scope 有两个值:
- Prototype:当调用 getBean 方法的时候创建对象
- Singleton:当加载配置文件的时候创建单例对象
还有 2 个属性:
- Request:创建时放到 request 域中
- Session:创建时放到会话里
<!-- Scope 有两个值:-->
<!-- Prototype:当调用 getBean 方法的时候创建对象-->
<!-- Singleton:当加载配置文件的时候创建单例对象-->
<!-- 还有 2 个属性:-->
<!-- Request:创建时放到 request 域中-->
<!-- Session:创建时放到会话里-->
<bean id="myFactory" class="Bean.MyFactoryBean" scope="prototype">
</bean>
Bean 的生命周期
后置处理器能干啥
后置处理器有俩方法
这两个方法的执行顺序一个在初始化方法之前
一个在初始化方法之后
无后置处理器
(1).无参构造器
(2).属性赋值
(3).初始化方法
(4).创建对象
(5).销毁方法
工具类
package Bean;
public class BeanLife {
private String name;
@Override
public String toString() {
return "BeanLife{" +
"name='" + name + '\'' +
'}';
}
public BeanLife(String name) {
System.out.println("第二步属性赋值");
this.name = name;
}
public BeanLife() {
System.out.println("第一步无参构造");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("第二步属性赋值");
this.name = name;
}
public void initMethod(){
System.out.println("第三步初始化方法");
}
public void destroy(){
System.out.println("第五步销毁方法");
}
}
xml文件
<bean id="beanlife" class="Bean.BeanLife" init-method="initMethod" destroy-method="destroy">
<property name="name" value="nana"/>
</bean>
测试
@Test
public void beanlife_test(){
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
BeanLife beanlife = classPathXmlApplicationContext.getBean("beanlife", BeanLife.class);
System.out.println("第四步创建对象");
String s = beanlife.toString();
System.out.println(s);
classPathXmlApplicationContext.close();
}
有后置处理器
(1).无参构造器
(2).属性赋值
(3). 将 Bean 实 例 传 入 到 后 置 处 理 器
postProcessBeforeInitializatiion 方法中
(4).初始化方法
(5). 将 Bean 实 例 传 入 到 后 置 处 理 器
postProcessAfterInitialization 方法中
(6).创建对象
(7).销毁方法
整一个后置处理器
package Bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
System.out.println("执行继承BeanPostProcessor的postProcessBeforeInitialization方法");
return o;
}
@Override
public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
System.out.println("执行继承BeanPostProcessor的postProcessAfterInitialization方法");
return o;
}
}
在xml里面配置一下
<bean id="myPostProcessor" class="Bean.MyPostProcessor"/>
测试
spring检测到你配置了后置处理之后再spring执行的创建所有实例对象的时候都会使用这个后置处理器
同样的 你配置了bean的生命周期之后创建其他对象的时候也会再当时的生命周期触发这个
自动装配
我们还是以部门和员工类来展示这个功能
部门类
package automatic;
//部门类
public class Dest {
private String name;
public Dest() {
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dest{" +
"name='" + name + '\'' +
'}';
}
}
员工类
package automatic;
//员工类
public class Emp {
private Dest dest;
public Dest getDest() {
return dest;
}
public void setDest(Dest dest) {
this.dest = dest;
}
@Override
public String toString() {
return "Emp{" +
"dest=" + dest +
'}';
}
}
配置文件
<!-- 自动装配 autowire="byName byType:根据属性类型赋值-->
<bean id="dest" class="automatic.Dest" >
<property name="name" value="this is i set name"/>
</bean>
<bean id="emp" class="automatic.Emp" autowire="byName">
</bean>
测试
@Test
public void automatic(){
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
Emp emp = classPathXmlApplicationContext.getBean("emp", Emp.class);
String s = emp.toString();
System.out.println(s);
}
XML 读取配置文件
Properties
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/text
username=root
password=Qwer1234
XML
<!--创建德鲁伊池对象并使用 EL 表达式读取配置文件注入属性-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${driverClassName}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</bean>
<!--需要导入头文件-->
<context:property-placeholder location="jdbcPro.properties"/>