Spring5 基础学习

下载Spring5

image-20230108191324198

下载地址:https://repo.spring.io/ui/native/release/org/springframework/spring/

image-20230108191604542

简单测试

image-20230108213301319

public class User {

public void add(){
System.out.println("hello");
}
}
############################################
<?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">

<!-- 配置user对象创建-->
<bean id="user" class="com.miao.testspring5.User"></bean>
</beans>
#################################################
public class TestSpring5 {

@Test
public void testUser(){
//加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//获取配置创建的对象
User user=context.getBean("user",User.class);
System.out.println(user);
user.add();
}
}

IOC容器

IOC底层原理

IOC概念

  1. 控制反转,把对象创建和对象之间的调用过程,交给spring管理
  2. 使用IOC目的:为了降低耦合度

IOC底层原理

xml解析、工厂模式、反射

简单图解

image-20230108220640287

IOC接口(BeanFactory)

IOC容器底层是 对象工厂

Spring 提供IOC容器实现的两种方式:(接口)

  1. BeanFactory:IOC容器基本实现,是spring内部的使用接口

    加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象

  2. ApplicationContext:BeanFactory接口的子接口,功能更强大

    加载配置文件时候就会将配置文件中的对象进行创建

  3. ApplicationContext:两个实现类

image-20230108222440216

IOC操作Bean管理(基于xml)

基于xml方式创建对象

  1. 在spring配置文件中,使用bean标签,标签里面添加对应属性,

    就可以实现对象创建。

  2. 在bean标签中有很多属性,常用属性:

    • id属性:唯一标识
    • class属性:类全路径(包类路径)
  3. 创建对象的时候,默认执行无参数构造方法完成对象创建

基于xml方式注入属性

  1. DI:依赖注入,注入属性
    • 方式一:使用set方法注入
    • 方式二:使用有参构造注入

使用set方法注入属性

//使用set方法注入属性
public class Book {
//创建属性
private String name;
private String author;
//创建属性对应的set方法
public void setName(String name) {
this.name = name;
}
public void setAuthor(String author) {
this.author = author;
}
public void testDemo(){
......
}
}
###########################################
# bean.xml中
<!-- set方法注入属性-->
<bean id="book" class="com.miao.testspring5.Book">
<!--
name:类里面属性名称
value:向属性注入值
-->
<property name="name" value="葵花宝典"></property>
<property name="author" value="东方不服"></property>
</bean>
###############################################
@Test
public void testBook(){
//加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//获取配置创建的对象
Book book=context.getBean("book",Book.class);
System.out.println(book);
book.testDemo();
}

使用有参构造注入属性

public class Order {
private String name;
private String address;

public Order(String name, String address) {
this.name = name;
this.address = address;
}
public void testDemo(){
System.out.println(name+"---------"+address);
}
}
##########################################
<!-- 配置order对象有参构造注入属性-->
<bean id="order" class="com.miao.testspring5.Order">
<constructor-arg name="name" value="马桶"></constructor-arg>
<constructor-arg name="address" value="made in china"></constructor-arg>
</bean>
###########################################
@Test
public void testOrder(){
//加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
//获取配置创建的对象
Order order=context.getBean("order",Order.class);
System.out.println(order);
order.testDemo();

}

P标签 set注入属性(了解)

image-20230109192051028image-20230109192122679

注入其它类型属性

null值

<!--注入空值-->
<bean id="book" class="com.miao.testspring5.Book">
<property name="name" value="葵花宝典"></property>
<property name="author" value="东方不服"></property>
<property name="address">
<null></null>
</property>
</bean>

属性值包含特殊符号

<!--
属性值包含特殊含义
1.把<>进行转义 &lt; &gt;
2.特殊内容写到 CDATA中
-->
<bean id="book" class="com.miao.testspring5.Book">
<property name="name" value="葵花宝典"></property>
<property name="author" value="东方不服"></property>
<property name="address">
<value> <![CDATA[
<<中国的宝贝>>
]]> </value>
</property>
</bean>

注册属性-外部bean

<!--    配置UserService和UserDao对象创建-->
<bean id="userService" class="com.miao.inner.service.UserService">
<!-- name属性:类 里面的属性名称
ref属性:创建UserDao对象 bean标签 id值-->
<property name="userDao" ref="userDao"></property>
</bean>
<bean id="userDao" class="com.miao.inner.dao.UserDaoImpl"></bean>
#######################################
public class UserService {

private UserDao userDao;

public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}

public void add(){
System.out.println("service add ----------");
userDao.update();
}
}
##################################################
public interface UserDao {
public void update();
}
###################################################
public class UserDaoImpl implements UserDao{
@Override
public void update() {
System.out.println("dao update -------");
}
}
######################################################
@Test
public void testUser(){
//加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
//获取配置创建的对象
UserService userService=context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}

注入属性-内部bean和级联关系

    @Test
public void testBean(){
//加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
//获取配置创建的对象
Emp emp=context.getBean("emp", Emp.class);
System.out.println(emp);
emp.add();
}
###############################
//部门类
public class Dept {
private String dname;

public void setDname(String dname) {
this.dname = dname;
}
public String toString(){
return "我的部门是"+dname;
}
}
#######################################
//员工类
public class Emp {
private String ename;
private String egender;
//员工属于某一个部门
private Dept dept;

public void setDept(Dept dept) {
this.dept = dept;
}

public void setEname(String ename) {
this.ename = ename;
}

public void setEgender(String egender) {
this.egender = egender;
}
public void add(){
System.out.println(ename+"--"+egender+"--"+dept);
}
}
#########################################
<!-- 配置Dept部门和 Emp员工对象创建-->

<!-- 内部bean-->
<bean id="emp" class="com.miao.bean.Emp">
<!-- 对象属性-->
<property name="dept" >
<bean id="dept" class="com.miao.bean.Dept">
<property name="dname" value="销售"></property>
</bean>
</property>
<!-- 普通属性-->
<property name="ename" value="张三"></property>
<property name="egender" value="nan"></property>
</bean>

注入属性-级联

image-20230109223655471

image-20230109223723506

注入属性-数组类型-集合类型

//属性注入 数组 集合
public class Stu {
//数组属性注入
private String[] cources;
//list属性注入
private List<String> list;
//map属性注入
private Map<String,String> maps;
//set属性注入
private Set<String> set;

public void setCources(String[] cources) {
this.cources = cources;
}

public void setList(List<String> list) {
this.list = list;
}

public void setMaps(Map<String, String> maps) {
this.maps = maps;
}

public void setSet(Set<String> set) {
this.set = set;
}
public void test(){
System.out.println(Arrays.toString(cources));
System.out.println(list);
System.out.println(maps);
System.out.println(set);
}
}
#######################################################
<!--对象注入-->
<bean id="stu" class="com.miao.collection.Stu">
<!-- 数组属性注入-->
<property name="cources">
<array>
<value>java</value>
<value>nodejs</value>
</array>
</property>
<!-- 集合属性注入-->
<property name="list">
<list>
<value>html</value>
<value>javascript</value>
</list>
</property>
<property name="set">
<set>
<value>vue</value>
<value>vue3.0</value>
</set>
</property>
<property name="maps">
<map>
<entry key="Hexo" value="hexo"></entry>
<entry key="Php" value="php"></entry>
</map>
</property>
</bean>
#####################################################

注入对象属性 在集合中

<!--对象注入-->
<bean id="stu" class="com.miao.collection.Stu">
<property name="courseList">
<list>
<ref bean="course"></ref>
<ref bean="course1"></ref>
</list>
</property>
</bean>
<bean id="course" class="com.miao.collection.Course">
<property name="cname" value="剑术"></property>
</bean>
<bean id="course1" class="com.miao.collection.Course">
<property name="cname" value="太极"></property>
</bean>
########################################
//course对象属性注入
private List<Course> courseList;
//set方法注入
public void setCourseList(List<Course> courseList) {
this.courseList = courseList;
}

集合注入部分提取


public class Book {
private List<String> list;

public void setList(List<String> list) {
this.list = list;
}
public String toString(){
return "书籍是:"+list+"\t\t";
}
}
##############################################
<util:list id="booklist">
<value>小王子</value>
<value>中王子</value>
<value>大王子</value>
</util:list>
<bean id="book" class="com.miao.collection.Book">
<property name="list" ref="booklist"></property>
</bean>
######################################

需要改的地方(提取注入部分)

image-20230110192645094

IOC操作bean管理(FactoryBean)

spring有两种类型bean,普通bean,工厂bean(factorybean)

普通bean:在配置文件中定义bean类型就是返回类型

工厂bean:在配置文件中定义bean类型可以和返回类型不一样

  • 创建类,实现接口factorybean
  • 实现接口里面的方法,在方法中定义返回的bean类型
public class FacBean implements FactoryBean<Course> {
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("缘起,人群中看见你");
return course;
}

@Override
public Class<?> getObjectType() {
return null;
}

@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
################################################
<!-- 配置FacBean对象-->
<bean id="facBean" class="com.miao.factorybean.FacBean">
</bean>
################################################
@Test
public void testFacBean(){
//加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("facbean.xml");
//获取配置创建的对象
Course course=context.getBean("facBean", Course.class);
System.out.println(course);

}
}

IOC操作Bean管理-bean作用域

在spring中,默认情况下,bean是单例对象

image-20230110213034805

image-20230110213118399

image-20230110213154895

设置单实例和多实例

  • spring配置文件bean标签里面属性(scope)
    1. singleton:单实例对象
    2. prototype:多实例对象

image-20230110213703521

image-20230110213728456

singleton和prototype的区别

  • singleton时:加载spring配置文件时就会创建单实例对象
  • prototype时:不会在加载spring配置文件时创建对象,在调用getbean方法 时创建多实例对象

image-20230110214347024

IOC操作Bean管理-bean生命周期

生命周期:

  • 对象创建到对象销毁的过程

bean生命周期

  1. 通过构造器创建bean实例(无参构造)
  2. 为bean的属性设置值和对其他bean的引用(调用set方法)
  3. 调用bean的初始化方法(需要配置初始化方法)
  4. bean可以使用了(对象获取了)
  5. 容器关闭时候,调用bean的销毁方法(配置销毁的方法)
package com.miao.bean;

public class Order {
private String oname;

public Order() {
System.out.println("第一步,调用无参方法创建对象");
}

public void setOname(String oname) {
this.oname = oname;
System.out.println("第二步,set方法属性注入");
}
public void initMethod(){
System.out.println("第三步,调用bean的初始化方法");
}
public void destoryMethod(){
System.out.println("第五步,调用bean的销毁方法");
}
}
#########################################
<!-- bean 的生命周期-->
<bean id="order" class="com.miao.bean.Order" init-method="initMethod" destroy-method="destoryMethod">
<property name="oname" value="bean生命周期"></property>
</bean>
#############################################
@Test
public void testBean1(){
//加载spring配置文件
// ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
//获取配置创建的对象
Order order=context.getBean("order", Order.class);
System.out.println("第四步,获取创建bean的实例对象");
System.out.println(order);
//主动销毁
context.close();
}

bean的后置处理器

  1. 通过构造器创建bean实例(无参构造)
  2. 为bean的属性设置值和对其他bean的引用(调用set方法)
  3. 把bean实例传递bean后置处理器方法(postProcessBeforeInitialization)
  4. 调用bean的初始化方法(需要配置初始化方法)
  5. 把bean实例传递bean后置处理器方法(postProcessAfterInitialization)
  6. bean可以使用了(对象获取了)
  7. 容器关闭时候,调用bean的销毁方法(配置销毁的方法)

image-20230110223125977

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="order" class="com.miao.bean.Order" init-method="initMethod" destroy-method="destoryMethod">
<property name="oname" value="bean生命周期"></property>
</bean>
<!-- 配置bean后置处理器-->
<bean id="myBeanPost" class="com.miao.bean.MyBeanPost"></bean>

IOC操作Bean管理(基于注解)

IOC操作Bean管理-xml自动装配

自动装配:

根据装配规则(属性名称或者属性类型),spring自动匹配属性值进行注入

<!--实现自动装配
bean标签属性,实现自动装配
autowire常用俩个值
byName:根据属性名称注入,注入bean的id值和类属性名称一样
byType:根据类型注入

-->
<bean id="emp" class="com.miao.autowire.Emp" autowire="byName"></bean>

<bean id="dept" class="com.miao.autowire.Dept"></bean>
################################################
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("自动装配属性");
}
}
####################################################
public class Dept {
}
######################################################
@Test
public void testAutowire(){
//加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("autowire.xml");
//获取配置创建的对象
Emp emp=context.getBean("emp", Emp.class);
System.out.println(emp.toString());
emp.test();

}

IOC操作Bean管理-引入外部文件

直接配置数据库信息

<!--    直接配置 数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/school"></property>
<property name="name" value="root"></property>
<property name="password" value="123456"></property>
</bean>

引入外部属性文件配置数据源连接池

image-20230111192106190

<!--    引入外部属性文件-->
<context:property-placeholder location="classpath: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>

IOC操作Bean管理-基于注解

spring针对bean管理中==创建对象==提供注解

  • @component

  • @service

  • @controller

  • @repository

    注解功能都是一样的

基于注解创建对象

  • 引入依赖

    spring-aop-xx.jar

  • 开启组件扫描

image-20230111210744861

#####################################################
<!--开启组件扫描
1.扫描多个包,使用`,`隔开
2.扫描包的上层目录
-->
<context:component-scan base-package="com.miao"></context:component-scan>

测试一波

//value值 相当于id值 <bean id="userService" class=""></bean>
//@Service相当于 xx.xml文件中的bean对象
@Service(value = "userService")
public class UserService {
public void add(){
System.out.println("userService add---------------");
}
}
################################################
<!--开启组件扫描
1.扫描多个包,使用`,`隔开
2.扫描包的上层目录
-->
<context:component-scan base-package="com.miao.annotation"></context:component-scan>
#############################################
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("annotation.xml");
UserService userService = context.getBean("userService", UserService.class);
System.out.println(userService);
userService.add();
}

基于注解方式实现属性注入

  • @autowired:根据属性类型注入
  • @qualifier:根据属性名称注入
  • @resource:可以根据名称和类型注入属性
  • @value:注入普通类型属性

使用注解的目的:简化xml配置

@autowired–根据属性类型进行注入

public interface UserDao {
public void add();
}
######################################
@Repository(value = "laoda") //相当于在bean中创建对象
public class UserDaoImpl implements UserDao{
@Override
public void add() {
System.out.println("userdao add-----------");
}
}
############################################
//value值 相当于id值 <bean id="userService" class=""></bean>
//@Service相当于 xx.xml文件中的bean对象
@Service(value = "userService")
public class UserService {
/*
定义dao类型属性
不需要添加set方法
添加注入 属性注解
*/
// @Qualifier("laoda")//根据名称进行注入
@Autowired
private UserDao userDao;
public void add(){
System.out.println("userService add---------------");
userDao.add();
}
}

@qualifier–根据名称进行属性注入,需要搭配@autowired 一起使用

image-20230111215848445

image-20230111215942950

@resource:可以根据类型或者名称注入

image-20230111220535718

autowired 和 resource 的小区别

image-20230111220735045

@value

image-20230111221402645

完全注解开发

创建配置类,代替xml配置文件

@Configuration //作为配置类,替代xml配置文件
//相当于替换xml中的<context:component-scan base-package="com.miao.annotation"></context:component-scan>
@ComponentScan(basePackages = {"com.miao.annotation"})
public class SpringConfig {
}

测试

image-20230111222517437

Aop

aop概念

  1. 面向切面编程
  2. 理解:在不通过修改源代码情况下,主干部分添加一个新功能

aop底层原理–两种情况动态代理

有接口情况,使用JDK动态代理

image-20230111225020488

没有接口

image-20230111225505797

jdk动态代理实现

调用newProxyInstance方法

//定义一个接口
public interface UserDao {
int add(int a,int b);
String update(String id);
}
###############################################
//实现类
public class UserDaoImpl implements UserDao{
@Override
public int add(int a, int b) {
System.out.println("add方法执行了---------");
return a+b;
}

@Override
public String update(String id) {
System.out.println("update方法执行了---------");
return id;
}
}
###################################################
package com.miao.newproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

//慢慢理解
public class JDKProxy {
public static void main(String[] args) {
//创建接口类 代理对象
Class[] interfaces = {UserDao.class};

UserDaoImpl userDao = new UserDaoImpl();
UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
// int res = dao.add(1, 2);
// System.out.println("res:--"+res);
String update = dao.update("22");
System.out.println(update);
}
}
//创建代理对象 代码
class UserDaoProxy implements InvocationHandler{

//将需要代理的对象 传递过来
//有参构造传递
//这里代理的是UserDaoImpl,用Object代替了
private Object obj;
public UserDaoProxy(Object obj){
this.obj=obj;
}
//增强的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("方法之前执行。。。。。。。。"+method.getName()+":传递的参数"+ Arrays.toString(args));
//被增强的方法执行
Object result = method.invoke(obj, args);
//方法之后
System.out.println("方法之后执行。。。。。。。。"+obj);
return result;
}
}

结果

image-20230111234021397

AOP术语

  1. 连接点

    类里面哪些方法可以被增强,这些方法称为连接点

  2. 切入点

    实际被真正增强的方法,称为切入点

  3. 通知(增强)

    实际增强的逻辑部分称为通知

    通知的类型:

    1. 前置通知
    2. 后置通知
    3. 环绕通知
    4. 异常通知
    5. 最终通知
  4. 切面

    把通知应用到切入点的过程

AOP操作

spring框架一般基于aspectj实习AOP操作

  • aspectj不是spring组成部分,独立AOP框架,一般aspectj和spring框架一起使用,进行aop操作

基于aspectj实现aop操作

  • 基于xml配置文件实现
  • 基于注解方式实现

切入点表达式:

  • 语法结构:

    execution([][][权限修饰符] [返回类型] [类全路径] [方法名称] ([参数列表]) )

基于注解实现

//被增强的类
@Component //相当于bean中创建实例
public class User {

public void add(){
System.out.println("add 方法------------");
}
}
####################################################
//需要增强的类
@Component
@Aspect //生成代理对象
public class UserProxy {

//前置通知:before注解
@Before(value = "execution(* com.miao.aopannotation.User.add(..))")
public void before(){
System.out.println("before执行了");
}
}
########################################################
<!--开启组件扫描
1.扫描多个包,使用`,`隔开
2.扫描包的上层目录
-->
<context:component-scan base-package="com.miao.aopannotation"></context:component-scan>
<!-- 开启aspectj代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
###################################################
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("aopannotation.xml");
User user = context.getBean("user", User.class);
user.add();
}

image-20230112220245419

image-20230112220256523


//需要增强的类
@Component
@Aspect //生成代理对象
public class UserProxy {

//前置通知:before注解
@Before(value = "execution(* com.miao.aopannotation.User.add(..))")
public void before(){
System.out.println("before执行了");
}
//后置通知:before注解
@After(value = "execution(* com.miao.aopannotation.User.add(..))")
public void after(){
System.out.println("After.............");
}
//前置通知:before注解
@AfterReturning(value = "execution(* com.miao.aopannotation.User.add(..))")
public void afterReturning(){
System.out.println("AfterReturning执行了");
}
//前置通知:before注解
@AfterThrowing(value = "execution(* com.miao.aopannotation.User.add(..))")
public void afterThrowing(){
System.out.println("AfterThrowing执行了");
}
//环绕通知:before注解
@Around(value = "execution(* com.miao.aopannotation.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("Around之前执行了");

//被增强的方法
proceedingJoinPoint.proceed();
System.out.println("Around之后执行了");
}
}

image-20230112221956234

异常通知

image-20230112222031579

image-20230112222110187

注意点–相同切入点抽取

image-20230112222705104

注意点–多个增强类对同一个方法增强,设置增强类优先级

在增强类上面添加注解@order(数字类型值),数字越小优先级越高

image-20230112223701746

image-20230112223753922

完全注解开发

image-20230112230235200

JdbcTemplate

事务管理