spring基础知识
环境搭建
创建子模块
之后在弹出的框中配置好
在spring-first的pom.xml加入
<dependencies>
<!-- spring context依赖-->
<!-- 当你引入spring Context后,表示将spring的基础依赖引入了-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.2</version>
</dependency>
<!-- junit5-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.3.1</version>
</dependency>
</dependencies>
更新maven依赖,记得换源
在spring-first中的src java里面建包
起名spring6
在里面建个类
package spring6;
public class User {
public void add(){
System.out.println("add...");
}
}
在resource创建xml配置
之后配置文件xml就初始化好了
这个xml具体作用是:自动创建对象
比如说以前要这样New一个对象
public static void main(String[] args) {
User user = new User();
user.add();
}
用Bean.xml可以使用bean标签创建对象,像这样:
<!--完成user对象创建-->
<!-- bean标签-->
<!-- 1.id 书写:唯一标识符-->
<!-- 2.clas 属性:要创建对象所在类的全路径(包名称+类名称)-->
<bean id = "user" class="spring6.User"></bean>
添加后,我们新建一个类写一个方法进行测试
package spring6;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
@Test
public void testUserObject(){
// 加载spring配置文件,对象创建
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");//配置文件名
// 获取创建对象
User user = (User) context.getBean("user");//bean id
System.out.println(user);
//使用对象调用方法进行测试
user.add();
}
}
总的说就是这样
如果在这里面写无参构造方法
无参构造方法将会被执行
这样新建对象的本质
底层新建对象的流程如下
1.bean.xml配置
2.加载bean.xml
3.反射构造一个类
4.将对象储存于 Map<String, BeanDefinition> beanDefinitionMap
说到这复习了一下反射
// 获取类Class对象
Class aClass = Class.forName("spring6.User");
User user = (User) aClass.getDeclaredConstructor().newInstance();
System.out.println(user);
Log4j2
apache的一个日志组件,我们将对他的日志信息优先级、输出方式(控制台/文件)、输出格式进行配置
一般而言。优先级
优先级高的会优先输出,如果设置了xx,只会输出优先级大于等于xx的信息
环境搭建
pom.xml
<!-- log4j2依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.19.0</version>
</dependency>
log4j2.xml (resources目录下)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
</Appenders>
<!-- <File name="log" fileName="./test.log" append="false">-->
<!-- <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>-->
<!-- </File>-->
<Loggers>
<Root level="DEBUG">
<AppenderRef ref="Console"/>
</Root>
</Loggers>
</Configuration>
测试成功
输出到文件报错了,以后用到再回来学
如果要手动输出到日志,是这样
比较少见,不演示了
Ioc-xml模式
一种面向对象的设计思想,中文为控制反转
意思是通过IoC容器来管理java对象的实例化和初始化,控制对象与对象之间的依赖关系,
由IoC容器管理的java对象称为String Bean
容器房bean,用map集合
xml配置文件 Bean定义信息(BeanDefinition)
抽象 BeanDefinitionReader
IoC容器 Bean定义信息 实例化 BeanFactory工厂+反射
初始化 最终对象
DI依赖注入
DI(Dependency Injection)指Spring创建对象的过程中,将对象依赖属性通过配置进行注入
实现方式:
- set注入
- 构造注入
IOC是一种控制反转的思想,而DI是对IoC的一种具体实现
具体实现:
BeanFactory是其具体实现,但是不对外开放,我们可以操作它的子接口ApplicationContext
https://www.cnblogs.com/tanghaorong/p/13432008.html
注解也继承了ApplicationContext
IOC环境搭建
在父项目中新建一个项目spring-ioc-xml
在父项目的pom中把之前的依赖引入,原来子项目的依赖会自动引入,可以删了
<dependencies>
<!-- spring context依赖-->
<!-- 当你引入spring Context后,表示将spring的基础依赖引入了-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.2</version>
</dependency>
<!-- junit5-->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.6.3</version>
</dependency>
<!-- log4j2依赖-->
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.19.0</version>
</dependency>
</dependencies>
在这个新建的项目中,new一个xml配置
叫bean.xml,新建后记得按右上角那个东西
然后建一个包com.thaistudyspring.iocxml
User.class
package com.thaistudyspring.iocxml;
public class User {
private String name;
private Integer age;
public void run(){
System.out.println("run......");
}
}
bean.xml
<bean id = "user" class = "com.thaistudyspring.iocxml.User"></bean>
TestUser
package com.thaistudyspring.iocxml;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
ApplicationContext cont = new ClassPathXmlApplicationContext("bean.xml");
// 根据id获取bean
User user = (User) cont.getBean("user");
System.out.println("根据id获取bean: " + user);
// 根据类型获取bean
User user1 = (User)cont.getBean(User.class);
System.out.println("根据类型获取bean: " + user1);
// 根据id和类型
User user2 = cont.getBean("user", User.class);
System.out.println("根据id和类型: " + user2);
}
}
跑一下,成功,截图不放了
- 实验1:当一个类型有多个类实现时,还可以使用类型获取这个类吗
bean.xml
<bean id = "user" class = "com.thaistudyspring.iocxml.User"></bean>
<bean id = "user1" class = "com.thaistudyspring.iocxml.User"></bean>
运行报错
用类型去获取bean就会报错了,因为它只能获取单个bean实例,而这里有多个实现对象
- 实验2:接口是否也可以获取到其实现的类
接口是否也可以获取到其实现的类呢,答案是可以的
bean.xml
<!--根据接口也能获取到类-->
<bean id = "userDaoImpl" class="com.thaistudyspring.iocxml.bean.UserDaoImpl"></bean>
写一个userDao接口
package com.thaistudyspring.iocxml.bean;
public interface UserDao {
public void run();
}
写一个实现(注意快捷键
package com.thaistudyspring.iocxml.bean;
public class UserDaoImpl implements UserDao{
@Override
public void run() {
System.out.println("thaiTest UserDaoImpl !");
}
}
测试类
package com.thaistudyspring.iocxml.bean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUserDao {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
// 根据类型获取接口对应的bean
UserDao userDao = context.getBean(UserDao.class);
System.out.println(userDao);
}
}
但是如果接口有多个实现类,就不可以根据接口类型获取这个类(参考实验1)
setting和构造器
bean往往有setting和构造器,如何通过xml直接new一个已经设置好属性的对象呢?
比如说book类(alt + insert 生成setter/getter/构造方法)
package com.thaistudyspring.iocxml.di;
public class Book {
private String bname;
private String author;
//生成set方法
public Book() {
}
public Book(String bname, String author) {
this.bname = bname;
this.author = author;
}
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
@Override
public String toString() {
return "Book{" +
"bname='" + bname + '\'' +
", author='" + author + '\'' +
'}';
}
public static void main(String[] args) {
Book book = new Book();
// set方法
book.setBname("jvav");
book.setAuthor("tha1");
// 构造器注入
Book book2 = new Book("jvav", "tha1");
}
}
通过xml可以这样设置
bean-di.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">
<!-- set 方法注入-->
<bean id = "book" class="com.thaistudyspring.iocxml.di.Book">
<property name="bname" value="前端开发"></property>
<property name="author" value="tha1"></property>
</bean>
</beans>
TestBook.java
package com.thaistudyspring.iocxml.di;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestBook {
@Test
public void testSetter() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
Book book = context.getBean("book", Book.class);
System.out.println(book);
}
}
还有一种方法,就是使用构造器进行注入
bean-di.xml (记得把前面的注释掉,不然也会new
<!-- 构造器注入-->
<bean id="bookCon" class="com.thaistudyspring.iocxml.di.Book">
<constructor-arg name = "bname" value="java开发"></constructor-arg>
<constructor-arg name = "author" value="tha1"></constructor-arg>
</bean>
测试
@Test
public void testConstructor() {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-di.xml");
Book book = context.getBean("bookCon", Book.class);
System.out.println(book);
}
特殊值处理
- 字面量赋值,示例如下
<bean id = "book" class="com.thaistudyspring.iocxml.di.Book">
<property name="bname" value="前端开发"></property>
<property name="author" value="tha1"></property>
</bean>
- 空值
如何给一个属性赋空值
<bean id = "book" class="com.thaistudyspring.iocxml.di.Book">
<property name="bname" value="前端开发"></property>
<property name="author"><null/></property>
</bean>
- xml
如果双引号也要写标签符,用实体编码
<
>
如下:
<bean id = "book" class="com.thaistudyspring.iocxml.di.Book">
<property name="bname" value="前端开发"></property>
<property name="author" value="<>"></property>
</bean>
- CDATA节
或者采用另一种xml特有的方法代替实体字符:CDATA节
格式是![CDATA[xxxxxxxxxx]]
a<b将被打印出来
<bean id = "book" class="com.thaistudyspring.iocxml.di.Book">
<property name="bname" value="前端开发"></property>
<property name="author">
<value><![CDATA[a<b]]></value>
</property>
</bean>
特殊类型
1.对象
测试demo
package com.thaistudyspring.iocxml.ditest;
public class Dept {
private String dname;
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public void info(){
System.out.println("部门名称: " + dname);
}
}
package com.thaistudyspring.iocxml.ditest;
public class Emp {
// 员工属于哪个部门
private Dept dept;
private String ename;
private Integer age;
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public void work(){
System.out.println(ename + " is working for " + age);
dept.info();
}
}
- 第一种方法是外部引入bean
bean-ditest.xml
<!-- 创建两个类对象-->
<!-- 在emp的bean标签哩,使用property引入dept的bean-->
<!-- -->
<bean id="dept" class="com.thaistudyspring.iocxml.ditest.Dept">
<property name="dname" value="安保部"></property>
</bean>
<bean id="emp" class="com.thaistudyspring.iocxml.ditest.Emp">
<!-- 普通属性注入-->
<property name="ename" value="lucy"></property>
<property name="age" value="50"></property>
<!--注入对象属性-->
<property name="dept" ref="dept"></property>
</bean>
主要就是先new一个对象,然后用ref(注意不是value)引入这个beanid
package com.thaistudyspring.iocxml.ditest;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
public class TestDi {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-ditest.xml");
Emp emp = context.getBean("emp", Emp.class);
emp.work();
}
}
- 第二种方法是内部引入bean
<!-- 内部bean注入-->
<!-- 在emp的bean标签哩,再创建dept的bean标签-->
<!-- -->
<bean id="emp2" class="com.thaistudyspring.iocxml.ditest.Emp">
<!-- 普通属性注入-->
<property name="ename" value="lucy"></property>
<property name="age" value="50"></property>
<!--注入对象属性-->
<property name="dept">
<bean id="dept2" class="com.thaistudyspring.iocxml.ditest.Dept">
<property name="dname" value="安保部"></property>
</bean>
</property>
</bean>
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-ditest.xml");
Emp emp = context.getBean("emp2", Emp.class);
emp.work();
}
- 第三种 级联赋值
数组类型
比如说给emp加一个这个
public String[] getLoves() {
return loves;
}
<bean id="dept" class="com.thaistudyspring.iocxml.ditest.Dept">
<property name="dname" value="技术部"></property>
</bean>
<bean id="emp" class="com.thaistudyspring.iocxml.ditest.Emp">
<!-- 普通属性注入-->
<property name="ename" value="lucy"></property>
<property name="age" value="50"></property>
<!--注入对象属性-->
<property name="dept" ref="dept"></property>
<!-- 数组类型-->
<property name="loves">
<array>
<value>吃饭</value>
<value>睡觉</value>
<value>敲代码</value>
</array>
</property>
</bean>
集合类型
比如list类型
dept类
private List<Emp> empList;
...
public void info(){
System.out.println("部门名称: " + dname);
for (Emp emp:empList){
System.out.println(emp.getEname() + " is " + emp.getAge() + " years old");
}
}
xml
<bean id="emp1" class="com.thaistudyspring.iocxml.ditest.Emp">
<property name="ename" value="tha1"></property>
<property name="age" value="33"></property>
</bean>
<bean id="emp2" class="com.thaistudyspring.iocxml.ditest.Emp">
<property name="ename" value="tha2"></property>
<property name="age" value="28"></property>
</bean>
<bean id="dept" class="com.thaistudyspring.iocxml.ditest.Dept">
<property name="dname" value="技术部"></property>
<property name="empList">
<list>
<ref bean="emp1"></ref>
<ref bean="emp2"></ref>
</list>
</property>
</bean>
map集合
如果多个元素
数组bean类型
原本命名空间没有util,需要手动加入
package com.thaistudyspring.iocxml.dimap;
public class Teacher {
private String teacherId;
private String teacherName;
public String getTeacherId() {
return teacherId;
}
public void setTeacherId(String teacherId) {
this.teacherId = teacherId;
}
public String getTeacherName() {
return teacherName;
}
@Override
public String toString() {
return "Teacher{" +
"teacherId='" + teacherId + '\'' +
", teacherName='" + teacherName + '\'' +
'}';
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
}
package com.thaistudyspring.iocxml.dimap;
import java.util.List;
import java.util.Map;
public class Student {
private List<Lesson> lessonList;
private Map<String,Teacher> teacherMap;
private String sid;
public List<Lesson> getLessonList() {
return lessonList;
}
@Override
public String toString() {
return "Student{" +
"lessonList=" + lessonList +
", teacherMap=" + teacherMap +
", sid='" + sid + '\'' +
", sname='" + sname + '\'' +
'}';
}
public void setLessonList(List<Lesson> lessonList) {
this.lessonList = lessonList;
}
public Map<String, Teacher> getTeacherMap() {
return teacherMap;
}
public void setTeacherMap(Map<String, Teacher> teacherMap) {
this.teacherMap = teacherMap;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
private String sname;
public void run(){
System.out.println("学生编号: " + sid + " 学生名称:" + sname);
System.out.println(teacherMap);
System.out.println(lessonList);
}
}
package com.thaistudyspring.iocxml.dimap;
public class Lesson {
private String lessonName;
public String getLessonName() {
return lessonName;
}
@Override
public String toString() {
return "Lesson{" +
"lessonName='" + lessonName + '\'' +
'}';
}
public void setLessonName(String lessonName) {
this.lessonName = lessonName;
}
}
重头戏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">
<!-- 1.创建3个对象-->
<!-- 2.-->
<bean id="teacherone" class="com.thaistudyspring.iocxml.dimap.Teacher">
<property name="teacherId" value="2333"></property>
<property name="teacherName" value="Qka"></property>
</bean>
<bean id="teachertwo" class="com.thaistudyspring.iocxml.dimap.Teacher">
<property name="teacherId" value="6667"></property>
<property name="teacherName" value="mikujacko"></property>
</bean>
<bean id="student" class="com.thaistudyspring.iocxml.dimap.Student">
<property name="sid" value="666"></property>
<property name="sname" value="tha1"></property>
<property name="lessonList" ref="lessonList"></property>
<property name="teacherMap" ref="teacherMap"></property>
</bean>
<util:list id="lessonList">
<ref bean="lessonone"></ref>
<ref bean="lessontwo"></ref>
</util:list>
<util:map id="teacherMap">
<entry>
<key>
<value>10010</value>
</key>
<ref bean="teacherone"></ref>
</entry>
<entry>
<key>
<value>10012</value>
</key>
<ref bean="teachertwo"></ref>
</entry>
</util:map>
<bean id="lessonone" class="com.thaistudyspring.iocxml.dimap.Lesson">
<property name="lessonName" value="java开发"></property>
</bean>
<bean id="lessontwo" class="com.thaistudyspring.iocxml.dimap.Lesson">
<property name="lessonName" value="前端开发"></property>
</bean>
</beans>
测试成功
命名空间
为了区别同名的变量,我们会在前面加上命名空间
demo
xmlns:p="http://www.springframework.org/schema/p"
在xml前面声明命名空间
<!-- p命名空间注入-->
<bean id="studentp" class="com.thaistudyspring.iocxml.dimap.Student" p:sid="100" p:sname="mary"
p:lessonList-ref="lessonList" p:teacherMap-ref="teacherMap"></bean>
特点就是p:xxxxx
这种格式,这是有命名空间的Bean的初始化格式
测试
ApplicationContext context = new ClassPathXmlApplicationContext("bean-diref.xml");
Student student = context.getBean("studentp", Student.class);
student.run();
测试成功
引入外部文件
比如数据库账号密码地址,可写在文件里,从而减少xml的冗余,此外,如果需要修改时,显然修改配置文件会比在xml里面修改要方便明了
- 引入依赖
<!-- mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<!-- 数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.31</version>
</dependency>
- 静态文件
一搬都是properties为后缀,放在resources目录
jdbc.properties
jdbc.user=root
jdbc.password=atguigu
jdbc.url=jdbc:mysql://localhost:3306/spring?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver
- 加载
bean-jdbc.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:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 完成数据库信息注入-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClassName" value="${jdbc.driver}"></property>
</bean>
</beans>
一方面我们依旧需要在头部进行声明xmlns:context="http://www.springframework.org/schema/context"
,http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
然后引入外部依赖(需要借助德鲁伊druid提供的类)
<?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:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 完成数据库信息注入-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClassName" value="${jdbc.driver}"></property>
</bean>
</beans>
使用${xxxxx}
语法进行传参
测试
@Test
public void demo1(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl("jdbc:mysql://localhost:3306/spring?serverTimezone=UTC");
druidDataSource.setUsername("root");
druidDataSource.setPassword("root");
System.out.println(druidDataSource.getUrl());
}
@Test
public void demo2(){
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("bean-jdbc.xml");
DruidDataSource datasource = classPathXmlApplicationContext.getBean(DruidDataSource.class);
System.out.println(datasource.getUrl());
}
都正常输出,
demo2是我们引入外部文件的例子
作用域(单实例和多实例)
默认是单实例!
bean-scope.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">
<!-- 通过scope属性配置单实例 多实例-->
<bean id="orders" class="com.thaistudyspring.iocxml.scope.Orders"
scope="singleton"></bean>
</beans>
Orders
package com.thaistudyspring.iocxml.scope;
public class Orders {
}
测试
package com.thaistudyspring.iocxml.scope;
import com.thaistudyspring.iocxml.dimap.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean-scope.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println(orders);
Orders orders1 = context.getBean("orders", Orders.class);
System.out.println(orders1);
}
}
输出了同一个地址对象
这就是单实例
多实例如下,修改一下scope
<bean id="orders" class="com.thaistudyspring.iocxml.scope.Orders"
scope="prototype"></bean>
对象地址不一样了
bean的生命周期
起一个新的包
User.class
package com.thaistudyspring.iocxml.lifecycle;
public class User {
private String name;
public User(){
System.out.println("1 bean调用无参构造");
}
public void initMethod(){
System.out.println("4 bean对象初始化,调用指定的初始化方法");
}
public void destroyMethod(){
System.out.println("7 bean对象销毁,调用指定的销毁方法");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("2 给bean对象设置属性值");
this.name = name;
}
}
bean-life.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 https://www.springframework.org/schema/util/spring-util.xsd">
<bean id="user" class="com.thaistudyspring.iocxml.lifecycle.User" scope="singleton"
init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="lucy"></property>
</bean>
</beans>
测试
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-life.xml");
User user = context.getBean("user", User.class);
System.out.println("6 bean对象创建完成了,可以使用了");
System.out.println(user);
context.close();
}
}
后置处理器
新建一个类MyBeanPost,需要继承BeanPostProcessor并实现postProcessBeforeInitialization和postProcessAfterInitialization(字面意思)
package com.thaistudyspring.iocxml.lifecycle;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3 bean后置处理器,初始化之前执行");
System.out.println(beanName + "::" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("5 bean后置处理器,初始化之后执行");
System.out.println(beanName + "::" + bean);
return bean;
}
}
new它就需要写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 https://www.springframework.org/schema/util/spring-util.xsd">
<bean id="user" class="com.thaistudyspring.iocxml.lifecycle.User" scope="singleton"
init-method="initMethod" destroy-method="destroyMethod">
<property name="name" value="lucy"></property>
</bean>
<bean id="myBeanPost" class="com.thaistudyspring.iocxml.lifecycle.MyBeanPost">
</bean>
</beans>
测试
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-life.xml");
User user = context.getBean("user", User.class);
System.out.println("6 bean对象创建完成了,可以使用了");
System.out.println(user);
context.close();
}
}
FactoryBean
当xml的class="xxxx"
指向继承factorybean的工厂类时,返回的是getObject的方法定义的类
常用于整合第三方框架
bean-factory.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">
<bean id="user" class="com.thaistudyspring.iocxml.factorybean.MyFactoryBean"></bean>
</beans>
package com.thaistudyspring.iocxml.factorybean;
import org.springframework.beans.factory.FactoryBean;
public class MyFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception{
return new User();
}
@Override
public Class<?> getObjectType(){
return User.class;
}
}
package com.thaistudyspring.iocxml.factorybean;
public class User {
}
package com.thaistudyspring.iocxml.factorybean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-factorybean.xml");
User user = context.getBean("user", User.class);
System.out.println(user);
}
}
虽然xml的class=MyFactoryBean,但输出的不是MyFactoryBean,而是getObject决定的User
自动装配
自动装配的特点是一句autowire就可以把相应的类自己new起来,不用在property里面写
先这么建类和接口
package com.thaistudyspring.iocxml.auto.dao;
public interface UserDao {
public void addUserDao();
}
package com.thaistudyspring.iocxml.auto.dao;
public class UserDaoImpl implements UserDao{
@Override
public void addUserDao(){
System.out.println("userDao方法执行了");
}
}
package com.thaistudyspring.iocxml.auto.service;
public interface UserService {
public void addUserService();
}
package com.thaistudyspring.iocxml.auto.service;
import com.thaistudyspring.iocxml.auto.dao.UserDaoImpl;
public class UserServiceImpl implements UserService{
private UserDaoImpl userDao;
public void setUserDao(UserDaoImpl userDao) {
this.userDao = userDao;
}
@Override
public void addUserService(){
System.out.println("userService方法执行了...");
// UserDaoImpl userDao = new UserDaoImpl();
// userDao.addUserDao();
userDao.addUserDao();
}
}
package com.thaistudyspring.iocxml.auto.controller;
import com.thaistudyspring.iocxml.auto.service.UserService;
import com.thaistudyspring.iocxml.auto.service.UserServiceImpl;
public class UserController {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void addUser(){
System.out.println("controller方法执行了...");
// 传统方法
// UserServiceImpl userService = new UserServiceImpl();
// userService.addUserService();
// 调用service的方法
userService.addUserService();
}
}
然后在外面new 一个test
package com.thaistudyspring.iocxml.auto;
import com.thaistudyspring.iocxml.auto.controller.UserController;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-auto.xml");
UserController usercontroller = context.getBean("usercontroller", UserController.class);
usercontroller.addUser();
}
}
Ioc-注解
注解是代码中的一种特殊标记
格式 @注解名称(属性1=属性值...)
类上面,属性上面,方法上面
环境搭建:开启组件扫描
<?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/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:component-scan base-package="com.thaistudyspring"></context:component-scan>
</beans>
package com.thaistudyspring.spring6.bean;
import org.springframework.stereotype.Component;
@Component(value="user") //<bean id="user" class="xxx">
public class User {
}
这几个注解在实际使用上没有区别,但是我们应尽可能遵守惯例
value="user"不写的话,默认id就是类首字母小写
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
User user = context.getBean("user", User.class);
System.out.println(user);
}
}
测试成功,可以看到我们不需要依赖xml了,而实际上企业中也大部分是用注解的方法进行
属性注入
先这么建
步骤:
1 bean对象创建
2 定义相关属性,在属性上添加注解
一般来说,都是controller->service->dao,所以我们建类的时候,会按照这个顺序,把类写在属性里(有点像pop链,也叫做调用链)
测试如下
package com.thaistudyspring.spring6.autorwired.controller;
import com.thaistudyspring.spring6.autorwired.service.UserService;
import com.thaistudyspring.spring6.autorwired.service.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
//注入service
@Autowired //根据类型找到对应对象,完成注入
private UserServiceImpl userServiceimpl;
public void add(){
System.out.println("controller......");
userServiceimpl.add();
}
}
package com.thaistudyspring.spring6.autorwired.dao;
public interface UserDao {
public void add();
}
package com.thaistudyspring.spring6.autorwired.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDaoImpl implements UserDao{
@Override
public void add() {
System.out.println("Dao.........");
}
}
package com.thaistudyspring.spring6.autorwired.service;
public interface UserService {
public void add();
}
package com.thaistudyspring.spring6.autorwired.service;
import com.thaistudyspring.spring6.autorwired.dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService{
@Autowired
private UserDaoImpl userDaoimpl;
@Override
public void add(){
System.out.println("service.......");
userDaoimpl.add();
}
}
package com.thaistudyspring.spring6.autorwired;
import com.thaistudyspring.spring6.autorwired.controller.UserController;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUserController {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
UserController bean = context.getBean(UserController.class);
bean.add();
}
}
运行成功
set方法注入
//注入service
// @Autowired //根据类型找到对应对象,完成注入
// private UserServiceImpl userServiceimpl;
// 第二种方法 set方法注入
private UserServiceImpl userServiceimpl;
@Autowired
public void setUserServiceimpl(UserServiceImpl userServiceimpl) {
this.userServiceimpl = userServiceimpl;
}
具体不演示了,idea傻逼了
构造方法注入
// // 第二种方法 set方法注入
// private UserServiceImpl userServiceimpl;
// @Autowired
// public void setUserServiceimpl(UserServiceImpl userServiceimpl) {
// this.userServiceimpl = userServiceimpl;
// }
// 第三章方式:构造方法注入
private UserServiceImpl userServiceimpl;
@Autowired
public UserController(UserServiceImpl userServiceimpl) {
this.userServiceimpl = userServiceimpl;
}
形参上进行注入
// 第三章方式:构造方法注入
// private UserServiceImpl userServiceimpl;
// @Autowired
// public UserController(UserServiceImpl userServiceimpl) {
// this.userServiceimpl = userServiceimpl;
// }
//第四章方式:形参注入
private UserServiceImpl userServiceimpl;
public UserController(@Autowired UserServiceImpl userServiceimpl) {
this.userServiceimpl = userServiceimpl;
}
只有一个有参构造
只有一个有参构造函数,@Autowired可以省略
注解联合
比如 AdminServerImpl和UserServiceImpl都继承UserService
如果这样写的话,不知道加载哪个
@Autowired
private UserService userServiceimpl;
用一个新的注解Qualifier,可以通过名称获取
//两个注解,根据名称注入
@Autowired
@Qualifier(value="adminServerImpl")
private UserService userServiceimpl;
Resource
Resource是jdk拓展包的,Autorwired是spring自带的,也就说Resource普适性更强
Resource 会先根据名称进行注入,如果没有再根据 属性类型 进行注入
Resource只能在属性上、setter方法上注入
jdk11以上需要引入这个依赖,jdk11以下不用
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
根据名称进行注入的例子如下
// 根据名称进行注入
@Resource(name = "myUserService")
private UserService userService;
@Service("myUserService")
public class UserServiceImpl implements UserService {
如果不指定名称,则默认找变量名名称进行注入
@Resource
private UserDao userMyDao;
@Repository("userMyDao")
public class UserDaoImpl implements UserDao {
变量名名称也找不到的话,则根据属性名称首字母小写(byType)
目录结构一样的
演示demo
package com.thaistudyspring.spring6.resource.controller;
import com.thaistudyspring.spring6.resource.service.UserService;
import com.thaistudyspring.spring6.resource.service.UserServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
@Controller("myUsercontroller")
public class UserController {
// 根据名称进行注入
@Resource(name = "myUserService")
private UserService userService;
public void add(){
System.out.println("controller......");
userService.add();
}
}
package com.thaistudyspring.spring6.resource.dao;
public interface UserDao {
public void add();
}
package com.thaistudyspring.spring6.resource.dao;
import org.springframework.stereotype.Repository;
@Repository("userMyDao")
public class UserDaoImpl implements UserDao {
@Override
public void add() {
System.out.println("Dao.........");
}
}
package com.thaistudyspring.spring6.resource.service;
public class AdminServerImpl implements UserService {
@Override
public void add() {
System.out.println("AdminServerImpl........");
}
}
package com.thaistudyspring.spring6.resource.service;
public interface UserService {
public void add();
}
package com.thaistudyspring.spring6.resource.service;
import com.thaistudyspring.spring6.resource.dao.UserDao;
import com.thaistudyspring.spring6.resource.dao.UserDaoImpl;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service("myUserService")
public class UserServiceImpl implements UserService {
@Resource
private UserDao userMyDao;
@Override
public void add(){
System.out.println("service.......");
userMyDao.add();
}
}
package com.thaistudyspring.spring6.resource;
import com.thaistudyspring.spring6.resource.controller.UserController;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestController {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
UserController bean = context.getBean("myUsercontroller",UserController.class);
bean.add();
}
}
spring全注解
全注解,不用xml的做法
就是加config包
写一个配置类
package com.thaistudyspring.spring6.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration //配置类
@ComponentScan("com.thaistudyspring.spring6") // 开启组件扫描,代替xml
public class SpringConfig {
}
TestController
package com.thaistudyspring.spring6.resource;
import com.thaistudyspring.spring6.config.SpringConfig;
import com.thaistudyspring.spring6.resource.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestController {
public static void main(String[] args) {
//ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserController bean = context.getBean("myUsercontroller",UserController.class);
bean.add();
}
}
手写IOC
回顾java反射
package com.thaistudyspring.reflect;
public class Car {
private String name;
private int age;
private String color;
public Car() {
}
public Car(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
private void run(){
System.out.println("私有方法-run...");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
Testclass自己测,知识写注释里了
//1、获取class对象多种方式
@Test
public void test01() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ClassNotFoundException {
//1 类名.class
Class clazz1 = Car.class;
//2 对象.getClass()
Class clazz2 = new Car().getClass();
//3 Class.forname(“全路径”)
Class clazz3 = Class.forName("com.thaistudyspring.reflect.Car");
//实例化
Car car = (Car)clazz3.getDeclaredConstructor().newInstance();
System.out.println(car);
}
//2、获取构造方法
@Test
public void test02(){
Class clazz = Car.class;
Constructor[] constructors = clazz.getConstructors();
for(Constructor c:constructors){
System.out.println("方法名称:" + c.getName() + " 参数个数:" + c.getParameterCount());
}
}
但是如果改为private
改为
private Car(String name, int age, String color) {
this.name = name;
this.age = age;
this.color = color;
}
我们演示一下如何拿到private方法
@Test
public void test02() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class clazz = Car.class;
// clazz.getConstructors(); 获取public构造方法
//Constructor[] constructors = clazz.getConstructors();
// clazz.getDeclaredConstructors() 获取所有构造方法 含public、private
Constructor[] constructors = clazz.getDeclaredConstructors();
for(Constructor c:constructors){
System.out.println("方法名称:" + c.getName() + " 参数个数:" + c.getParameterCount());
}
//指定有参数构造方法
//1 构造public
// Constructor constructor = clazz.getConstructor(String.class, int.class, String.class);
// Car car = (Car)constructor.newInstance("Benz", 10, "红色");
// System.out.println(car);
//2 构造private
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class, String.class);
declaredConstructor.setAccessible(true);
Car car = (Car)declaredConstructor.newInstance("捷达", 15, "白色");
System.out.println(car);
}