jdk使用17的版本
pom.xml
<!--这里必须要加 否则会报版本错误-->
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.2</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.2</version>
</dependency>
</dependencies>
控制反转(ioc):就是把new对象,交给spring来去new;
依赖注入(di): 就是对控制反转的具体实现
所谓的注入,就是给字段赋值
bean.xml就是对应BeanDefinition,叫做bean定义信息
要想读取这些bean.xml文件的内容就需要一个接口,就是BeanDefinitionReader
然后把这些bean交友ioc来管理
然后解析这些配置
可以通过BeanFactory+反射的方式来实例化(就是new对象)
实例化完,还不能直接使用这个对象,还需要进行初始化
就是set属性赋值
然后你在从上下文中去获取bean就有数据了
我们先来看下set注入
创建bean.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--id 随便定义,class 类路径 要在context.getBean("这里匹配上") -->
<bean id="a" class="com.dmg.A">
<!--属性 字段 值-->
<property name="name" value="张三"></property>
</bean>
</beans>
package com.dmg;
public class A {
private String name;
public A(){
System.out.println("无参构造A");
}
public void setName(String name) {
System.out.println("set注入");
this.name = name;
}
public String getName() {
return name;
}
public void add(){
System.out.println("add");
}
@Override
public String toString() {
return "A{" +
"name='" + name + '\'' +
'}';
}
}
public class B {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
A a=(A)context.getBean("a");
System.out.println(a);
a.add();
}
}
我们在来看下有参方法构造注入
对A类进行改造
public A(String name){
System.out.println("我是有参构造A");
this.name=name;
}
修改bean.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--id 随便定义,class 类路径 要在context.getBean("这里匹配上") -->
<bean id="a" class="com.dmg.A">
<!--有参构造注入 字段 值-->
<constructor-arg name="name" value="李四"></constructor-arg>
</bean>
</beans>
接下来我们在看下引用其他对象
package com.dmg;
public class A {
private String name;
private C cc;
public A(){
System.out.println("无参构造A");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public C getCc() {
return cc;
}
public void setCc(C cc) {
this.cc = cc;
}
@Override
public String toString() {
return "A{" +
"name='" + name + '\'' +
", cc=" + cc +
'}';
}
}
package com.dmg;
public class C {
private Integer age;
public C(){
System.out.println("无参构造c");
}
public void setAge(Integer age) {
this.age = age;
}
public Integer getAge() {
return age;
}
@Override
public String toString() {
return "C{" +
"age=" + age +
'}';
}
}
bean.xml中使用ref引用其他的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">
<!--id 随便定义,class 类路径 要在context.getBean("这里匹配上") -->
<bean id="a" class="com.dmg.A">
<property name="name" value="张三"></property>
<property name="cc" ref="c"></property>
</bean>
<bean id="c" class="com.dmg.C">
<property name="age" value="18"></property>
</bean>
</beans>
接下来我们在来看下map注入
package com.dmg;
import java.util.Map;
public class A {
private String name;
private Map<String,C> map;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map<String, C> getMap() {
return map;
}
public void setMap(Map<String, C> map) {
this.map = map;
}
@Override
public String toString() {
return "A{" +
"name='" + name + '\'' +
", map=" + map +
'}';
}
}
修改bean.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--id 随便定义,class 类路径 要在context.getBean("这里匹配上") -->
<bean id="a" class="com.dmg.A">
<property name="name" value="张三"></property>
<property name="map" >
<map>
<entry>
<key>
<value>1111</value>
</key>
<ref bean="c"></ref>
</entry>
<entry>
<key>
<value>2222</value>
</key>
<ref bean="c"></ref>
</entry>
</map>
</property>
</bean>
<bean id="c" class="com.dmg.C">
<property name="age" value="18"></property>
</bean>
</beans>
接下来我们在来看下list注入
package com.dmg;
import java.util.List;
import java.util.Map;
public class A {
private String name;
private List<C> list;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<C> getList() {
return list;
}
public void setList(List<C> list) {
this.list = list;
}
@Override
public String toString() {
return "A{" +
"name='" + name + '\'' +
", list=" + list +
'}';
}
}
修改bean.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--id 随便定义,class 类路径 要在context.getBean("这里匹配上") -->
<bean id="a" class="com.dmg.A">
<property name="name" value="张三"></property>
<property name="list">
<list>
<ref bean="c"></ref>
<ref bean="c"></ref>
</list>
</property>
</bean>
<bean id="c" class="com.dmg.C">
<property name="age" value="18"></property>
</bean>
</beans>
接下来我们在看下数组注入
package com.dmg;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class A {
private String name;
private String[]sz;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String[] getSz() {
return sz;
}
public void setSz(String[] sz) {
this.sz = sz;
}
@Override
public String toString() {
return "A{" +
"name='" + name + '\'' +
", sz=" + Arrays.toString(sz) +
'}';
}
}
修改bean.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--id 随便定义,class 类路径 要在context.getBean("这里匹配上") -->
<bean id="a" class="com.dmg.A">
<property name="name" value="张三"></property>
<property name="sz">
<array>
<value>1121</value>
<value>222</value>
</array>
</property>
</bean>
</beans>
接下来我们在来看下util标签注入
修改bean.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: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"
>
<!--id 随便定义,class 类路径 要在context.getBean("这里匹配上") -->
<bean id="a" class="com.dmg.A">
<property name="name" value="张三"></property>
<property name="list">
<util:list >
<ref bean="c"></ref>
<ref bean="c"></ref>
</util:list>
</property>
</bean>
<bean id="c" class="com.dmg.C">
<property name="age" value="222"></property>
</bean>
</beans>
接下来我们在看下来p标签 简写注入
修改bean.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:util="http://www.springframework.org/schema/util"
xmlns:p="http://www.springframework.org/schema/p"
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"
>
<!--id 随便定义,class 类路径 要在context.getBean("这里匹配上") -->
<bean id="a" class="com.dmg.A" p:name="张三" p:list-ref="list1">
</bean>
<util:list id="list1">
<ref bean="c"></ref>
<ref bean="c"></ref>
</util:list>
<bean id="c" class="com.dmg.C">
<property name="age" value="222"></property>
</bean>
</beans>
接下来我们看下引入外部属性文件
先在pom.xml加入
<!-- MySQL驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!-- 数据源 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.15</version>
</dependency>
创建jdbc.properties文件
jdbc.user=root
jdbc.password=123456
jdbc.url=jdbc:mysql://localhost:3306/dmg?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
修改bean.xml文件,使用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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--外部文件路径-->
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
<!--引入外部文件 通过占位符赋值-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="driverClassName" value="${jdbc.driver}"></property>
</bean>
</beans>
然后我们就能动态的修改外部的配置文件了
public class B {
public static void main(String[] args) {
ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
DruidDataSource druidDataSource=(DruidDataSource)context.getBean("druidDataSource");
System.out.println(druidDataSource.getUrl());
System.out.println(druidDataSource.getPassword());
}
}
接下来我们在来看下bean的作用域
pom.xml加入日志
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.13.3</version>
</dependency>
创建log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<loggers>
<!--
level指定日志级别,从低到高的优先级:
TRACE < DEBUG < INFO < WARN < ERROR < FATAL
trace:追踪,是最低的日志级别,相当于追踪程序的执行
debug:调试,一般在开发中,都将其设置为最低的日志级别
info:信息,输出重要的信息,使用较多
warn:警告,输出警告的信息
error:错误,输出错误信息
fatal:严重错误
-->
<root level="DEBUG">
<appender-ref ref="spring6log"/>
<appender-ref ref="RollingFile"/>
<appender-ref ref="log"/>
</root>
</loggers>
<appenders>
<!--输出日志信息到控制台-->
<console name="spring6log" target="SYSTEM_OUT">
<!--控制日志输出的格式-->
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
</console>
<!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用-->
<File name="log" fileName="d:/spring6_log/test.log" append="false">
<PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
</File>
<!-- 这个会打印出所有的信息,
每次大小超过size,
则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,
作为存档-->
<RollingFile name="RollingFile" fileName="d:/spring6_log/app.log"
filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
<PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
<SizeBasedTriggeringPolicy size="50MB"/>
<!-- DefaultRolloverStrategy属性如不设置,
则默认为最多同一文件夹下7个文件,这里设置了20 -->
<DefaultRolloverStrategy max="20"/>
</RollingFile>
</appenders>
</configuration>
public class A {
}
bean.xml 使用scope="singleton" 或者不写表示单例
<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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="a" class="com.dmg.A" scope="singleton">
</bean>
</beans>
我们可以看到在初始化的时候才创建单实例bean,在获取的时候不会创建
2个对象的地址都是一样的,这就是单实例
在bean.xml中改成多实例,scope="prototype"
可以看到2个对象的地址都不一样了
接下来我们来看下bean的生命周期
bean对象创建(调用无参构造器)
给bean对象设置属性
bean的后置处理器(初始化之前)
bean对象初始化(需要在配置bean时指定初始化方法)
bean的后置处理器(初始化之后)
bean对象就绪可以使用
bean对象销毁(需要在配置bean时指定销毁方法)
ioc容器关闭
public class A {
public A(){
System.out.println("1:无参构造");
}
private String name;
public void setName(String name) {
System.out.println("2:属性赋值");
this.name = name;
}
public void init(){
System.out.println("4:初始化");
}
public void xiaoHui(){
System.out.println("6:销毁");
}
}
创建自定义的bean后置处理器,这个后置处理器针对的是所有的ioc容器中的bean
/**
* 自定义后置处理器
*/
public class C implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3:初始化之前: "+beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("5:初始化之后:"+beanName);
return bean;
}
}
public class B {
public static void main(String[] args) {
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
A a=(A)context.getBean("a");
//销毁
context.close();
}
}
创建bean.xml
<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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="a" class="com.dmg.A" init-method="init" destroy-method="xiaoHui">
<property name="name" value="张三"></property>
</bean>
<bean id="c" class="com.dmg.C"></bean>
</beans>
生命周期总结:实例化(创建对象)->属性赋值->初始化->销毁
接下来我们在来看下工厂bean(FactoryBean),
就是可以创建对象,通过&前缀来返回不同的类
/**
* 自定义工厂bean
*/
public class MyFactoryBean implements FactoryBean<A> {
//创建对象
@Override
public A getObject() throws Exception {
return new A();
}
//返回对象类型
@Override
public Class<?> getObjectType() {
return A.class;
}
}
修改bean.xml
<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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="c" class="com.dmg.C"></bean>
<bean id="myFactoryBean" class="com.dmg.MyFactoryBean"></bean>
</beans>
public class B {
public static void main(String[] args) {
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
//加&前缀 返回的就是MyFactoryBean
System.out.println(context.getBean("&myFactoryBean"));
//不加前缀 返回的就是A 就是泛型中的类
System.out.println(context.getBean("myFactoryBean"));
}
}
接下来我们在来看下bean的自动装配
自动装配:根据指定的策略 在ioc容器中匹配某一个bean自动为指定的bean中所依赖的类类型或者接口类型 属性赋值
我们先来看下类型注入
public class MyController {
private MyService myService;
public void setMyService(MyService myService) {
System.out.println("set注入");
this.myService = myService;
}
public void add(){
System.out.println("控制层");
myService.add();
}
}
public interface MyService {
public void add();
}
public class MyServiceImpl implements MyService{
@Override
public void add() {
System.out.println("add");
}
}
修改bean.xml,使用 autowire="byType"就是根据类型注入
<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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myController" class="com.dmg.MyController" autowire="byType">
</bean>
<bean id="myServiceImpl" class="com.dmg.MyServiceImpl">
</bean>
</beans>
public class B {
public static void main(String[] args) {
ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
MyController myController=(MyController)context.getBean("myController");
myController.add();
}
}
接下来我们在来看下根据名称注入,改成
autowire="byName"
可以看到报错了,为啥呢?
因为和要这里的myService的名字一样
这次就可以了