尚硅谷javaSpring

news2024/10/9 15:18:29

尚硅谷课件:

分类:尚硅谷Spring6教程 - Lixx Blog - 李晓旭的博客

简介

Java Spring 是一个开源的、全面的企业级应用开发框架,旨在简化企业级应用的开发。Spring 框架最初由 Rod Johnson 在 2002 年发布,并随着时间的推移,它已经成为 Java 开发者中最受欢迎和广泛使用的框架之一。Spring 框架的核心是控制反转(IoC)和面向切面编程(AOP),这两个特性极大地提高了应用程序的模块性和可维护性。

Spring 框架的主要特点:

  1. 控制反转(IoC):IoC 是一种设计原则,用于减少计算机代码之间的耦合。在 Spring 中,IoC 容器负责管理对象(称为 beans)的生命周期和对象之间的关系。开发者不再需要编写大量的代码来创建对象之间的依赖关系,而是通过配置文件或注解来声明这些关系,由 Spring 容器在运行时动态地注入这些依赖。
  2. 面向切面编程(AOP):AOP 允许开发者将横切关注点(如日志、事务管理等)从业务逻辑中分离出来,从而提高了代码的可重用性和模块化。Spring AOP 提供了声明式的事务管理、日志记录等功能,使得这些横切关注点可以很容易地应用到多个地方,而无需修改业务代码。
  3. 模块化:Spring 框架被设计成高度模块化的,它包含多个模块,如 Spring Core、Spring MVC、Spring JDBC、Spring ORM 等,每个模块都提供了特定的功能。开发者可以根据需要选择性地使用这些模块,从而构建出满足自己需求的应用程序。
  4. 集成性:Spring 框架提供了与多种第三方库和框架的集成支持,如 Hibernate、MyBatis、JPA、Struts 等。这使得开发者可以很容易地将 Spring 与其他流行的技术栈结合使用,从而构建出功能强大的企业级应用。
  5. 测试支持:Spring 提供了对 JUnit 和 TestNG 等测试框架的集成支持,使得开发者可以很方便地对 Spring 应用进行单元测试、集成测试等。此外,Spring 还提供了 Mock 对象的功能,使得开发者可以在不依赖外部资源的情况下测试应用程序。

Spring 框架的应用场景:

Spring 框架适用于各种规模的企业级应用开发,包括但不限于:

  • Web 应用开发(使用 Spring MVC)
  • 数据访问(使用 Spring JDBC、Spring ORM)
  • 消息传递(使用 Spring Integration)
  • 批处理(使用 Spring Batch)
  • 云服务(使用 Spring Cloud)

总之,Java Spring 框架以其强大的功能、灵活的架构和广泛的社区支持,成为了 Java 开发者构建企业级应用的首选框架之一。

开发步骤

1.引入spring相关依赖

<?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>
    <parent>
        <groupId>com.ly.mybatis</groupId>
        <artifactId>spring6</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>spring-first</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--spring context依赖-->
        <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.2</version>
        </dependency>

        <!--junit测试-->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.6.3</version>
        </dependency>
    </dependencies>
</project>

2.创建类,定义属性和方法

package com.ly.spring;

import org.junit.jupiter.api.Test;

/**
 * @author 刘宇
 */
public class User {
    @Test
    public void add(){
        System.out.println("add");
    }
}

3.按照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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--完成user对象创建
        bean标签
            id属性:唯一标识
            class属性:要创建对象所在类的全路径
    -->
    <bean id="user" class="com.ly.spring.User"></bean>
</beans>

4.在spring配置文件配置相关信息

5.进行最终测试

package com.ly.spring.test;

import com.ly.spring.User;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 刘宇
 */
public class testUser {
    @Test
    public void testUserObject(){
        //加载spring配置文件,对象创建
        ApplicationContext context= new ClassPathXmlApplicationContext("bean.xml");
        //获取创建的对象
        User user=(User)context.getBean("user");
        System.out.println(user);
        //使用对象调用方法进行测试
        user.add();
    }
}

如何使用反射创建的对象

1.加载bean.xml配置文件

2.对xml文件进行解析操作

3.获取xml文件bean标签属性值id属性和class属性

4.使用反射根据类全路径创建对象

Class clazz=Class.forName("全类名");

Object o=clazz.newInstance();

整合log4j2日志框架

导入依赖

<!--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>

配置文件

<?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:\logs\springlog4j2" 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:\logs"
                     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>

容器:IoC

概述

1.控制反转(IoC)

控制反转是一种思想。

控制反转是为了降低程序耦合度,提高程序扩展力。

控制反转,反转的是什么?

1.将对象的创建权利交出去,交给第三方容器负责。

2.将对象和对象之间关系的维护权交出去,交给第三方容器负责。

控制反转这种思想如何实现呢?

  • DI(Dependency Injection):依赖注入

2.依赖注入

  • 依赖注入(Dependency Injection, DI)是一种设计模式,它指的是对象的依赖关系(即对象所需的外部资源或服务)不是由对象本身在内部创建或管理,而是由外部容器(如Spring框架的ApplicationContext)在创建对象时将其所需的依赖注入到对象中。

依赖注入常见的实现方式包括两种:

  • 第一种:set注入
  • 第二种:构造注入

所以结论是:IOC 就是一种控制反转的思想, 而 DI 是对IoC的一种具体实现。

Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。

3、IoC容器在Spring的实现

Spring 的 IoC 容器就是 IoC思想的一个落地的产品实现。IoC容器中管理的组件也叫做 bean。在创建 bean 之前,首先需要创建IoC 容器。Spring 提供了IoC 容器的两种实现方式:

①BeanFactory

这是 IoC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用。

②ApplicationContext

BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用 ApplicationContext 而不是底层的 BeanFactory。

③ApplicationContext的主要实现类

类型名 简介

ClassPathXmlApplicationContext 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象

FileSystemXmlApplicationContext 通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象

ConfigurableApplicationContext ApplicationContext 的子接口,包含一些扩展方法 refresh() 和 close() ,让 ApplicationContext 具有启动、关闭和刷新上下文的能力。

WebApplicationContext 专门为 Web 应用准备,基于 Web 环境创建 IOC 容器对象,并将对象引入存入 ServletContext 域中。

基于XML管理Bean

获取bean

1.id根据id获取bean

2.根据类型获取bean

3.根据id和类型获取

4.注意 当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个

<!--创建user对象-->
<bean id="user" class="com.ly.spring6.iocxml.User"></bean>
package com.ly.spring.test;

import com.ly.spring6.iocxml.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author 刘宇
 */
public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("bean.xml");
        //根据id获取bean
        User user1 =(User)context.getBean("user");
        System.out.println("根据id获取bean"+ user1);
        //根据类型获取bean
        User user2 = context.getBean(User.class);
        System.out.println("根据类型获取对象"+user2);
        //根据id和类型获取
        User user3 = context.getBean("user", User.class);
        System.out.println("根据id和类型获取bean"+user3);
    }
}
扩展知识

如果组件类实现了接口,根据接口类型可以获取 bean 吗?

可以,前提是bean唯一

如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?

不行,因为bean不唯一

结论

根据类型来获取bean时,在满足bean唯一性的前提下,其实只是看:『对象 instanceof 指定的类型』的返回结果,只要返回的是true就可以认定为和类型匹配,能够获取到。

java中,instanceof运算符用于判断前面的对象是否是后面的类,或其子类、实现类的实例。如果是返回true,否则返回false。也就是说:用instanceof关键字做判断时, instanceof 操作符的左右操作必须有继承或实现关系

依赖注入

1.setter注入

第一步:创建类,定义属性,创建构造器和set方法

第二步:在spring配置文件中进行配置

<!--set方法注入-->
<bean id="book" class="com.ly.spring6.iocxml.di.Book">
    <property name="bname" value="后端开发"></property>
    <property name="author" value="尚硅谷"></property>
</bean>
2.构造器注入

(1).创建有参构造

(2).配置spring文件

<!--构造器注入-->
<bean id="bookCon" class="com.ly.spring6.iocxml.di.Book">
  <constructor-arg name="bname" value="后端开发"></constructor-arg>
  <constructor-arg name="author" value="尚硅谷"></constructor-arg>
</bean>
注意:
<!--
constructor-arg标签还有两个属性可以进一步描述构造器参数:

index属性:指定参数所在位置的索引(从0开始)
name属性:指定参数名
3.特殊值处理

四种特殊值:1.字面量赋值 int a = 10 10就是字面量值

2.null值

3.xml实体 如"<>"解决方法1:进行转义处理如<转义为&lt;

4.CDATA实体

<property name="expression">
    <!-- 解决方案二:使用CDATA节 -->
    <!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
    <!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
    <!-- 所以CDATA节中写什么符号都随意 -->
    <value><![CDATA[a < b]]></value>
</property>
为对象类型属性赋值

方式一:引入外部bean

<bean id="dept" class="com.ly.spring6.iocxml.ditest.Dept">
  <property name="dname" value="安保部"></property>
</bean>
<bean id="emp" class="com.ly.spring6.iocxml.ditest.Emp">
  <property name="age" value="50"></property>
  <property name="ename" value="jack"></property>
  <!--注入对象类型
  private Dept dept
  使用ref标签,放入部门的id
  -->
  <property name="dept" ref="dept"></property>
</bean>

方式二:内部bean

<!--第二种方式内部bean-->
<bean id="emp2" class="com.ly.spring6.iocxml.ditest.Emp">
    <property name="age" value="50"></property>
    <property name="ename" value="jack"></property>
    <property name="dept">
        <bean id="dept2" class="com.ly.spring6.iocxml.ditest.Dept">
            <property name="dname" value="财务部"></property>
        </bean>
    </property>
</bean>

方式三:级联方式

<!--第三种方式级联赋值-->
<bean id="dept3" class="com.ly.spring6.iocxml.ditest.Dept">
    <property name="dname" value="技术研发部"></property>
</bean>

<bean id="emp3" class="com.ly.spring6.iocxml.ditest.Emp">
    <property name="ename" value="lans"></property>
    <property name="age" value="20"></property>
    <property name="dept" ref="dept3"></property>
    <property name="dept.dname" value="测试部"></property>
</bean>
4.数组类型赋值
<!--注入数组类型的属性-->
<bean id="dept" class="com.ly.spring6.iocxml.ditest.Dept">
    <property name="dname" value="技术部"></property>
</bean>
<bean id="emp" class="com.ly.spring6.iocxml.ditest.Emp">
    <property name="ename" value="luck"></property>
    <property name="age" value="20"></property>
    <!--对象类型-->
    <property name="dept" ref="dept"></property>
    <!--数组类型的属性-->
    <property name="loves">
        <array>
            <value>吃饭</value>
            <value>睡觉</value>
            <value>敲代码</value>
        </array>
    </property>
</bean>
5.List类型属性注入
<bean id="empone" class="com.ly.spring6.iocxml.ditest.Emp">
    <property name="ename" value="luck"></property>
    <property name="age" value="20"></property>
</bean>
<bean id="emptwo" class="com.ly.spring6.iocxml.ditest.Emp">
    <property name="ename" value="lu"></property>
    <property name="age" value="22"></property>
</bean>
<bean id="dept" class="com.ly.spring6.iocxml.ditest.Dept">
    <property name="dname" value="技术部"></property>
    <property name="empList">
        <list>
            <ref bean="empone"></ref>
            <ref bean="emptwo"></ref>
        </list>
    </property>
</bean>
6.map类型属性注入
<property name="teacherMap">
    <map>
        <entry>
            <key>
                <value>10010</value>
            </key>
            <ref bean="teacherone"></ref>
        </entry>
        <entry>
            <key>
                <value>10086</value>
            </key>
            <ref bean="teachertwo"></ref>
        </entry>
    </map>
</property>
7.引入集合bean注入
<!--
    创建对象
    注入普通类型属性
    使用util:类型定义
    在学生bean中引入util:类型定义bean,完成list map类型属性注入
-->
<bean id="student" class="com.ly.spring6.iocxml.dimap.Student">
    <property name="sid" value="100"></property>
    <property name="sname" value="luck"></property>
    <!--注入List和map类型属性-->
    <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>10086</value>
        </key>
        <ref bean="teachertwo"></ref>
    </entry>
</util:map>
<bean id="lessonone" class="com.ly.spring6.iocxml.dimap.Lesson">
    <property name="lessonName" value="java开发"></property>
</bean>
<bean id="lessontwo" class="com.ly.spring6.iocxml.dimap.Lesson">
    <property name="lessonName" value="前段开发"></property>
</bean>
<bean id="teacherone" class="com.ly.spring6.iocxml.dimap.Teacher">
    <property name="teacherName" value="西门"></property>
    <property name="teacherId" value="100"></property>
</bean>
<bean id="teachertwo" class="com.ly.spring6.iocxml.dimap.Teacher">
    <property name="teacherName" value="东门"></property>
    <property name="teacherId" value="200"></property>
</bean>
8.p命名空间

引入p命名空间

<?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/util
       http://www.springframework.org/schema/util/spring-util.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

引入p命名空间后,可以通过以下方式为bean的各个属性赋值

<bean id="studentp" class="com.ly.spring6.iocxml.dimap.Student"
      p:sid="100" p:sname="mary" p:lessonList-ref="lessonList" p:teacherMap-ref="teacherMap">
</bean>
9.引入外部属性文件

1.加入依赖

<!-- 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>

2.创建外部属性文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=ly

3.引入属性文件

<?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"/>

</beans>

注意:在使用 context:property-placeholder 元素加载外包配置文件功能前,首先需要在 XML 配置的一级标签 中添加 context 相关的约束。

4.配置bean

<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="url" value="${jdbc.url}"/>
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="username" value="${jdbc.user}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

5.测试

@Test

public void testDataSource() throws SQLException {

ApplicationContext ac = new ClassPathXmlApplicationContext("spring-datasource.xml");

DataSource dataSource = ac.getBean(DataSource.class);

Connection connection = dataSource.getConnection();

System.out.println(connection);

}

10.bean的作用域

可进行配置

<!-- scope属性:取值singleton(默认值),bean在IOC容器中只有一个实例,IOC容器初始化时创建对象 -->
<!-- scope属性:取值prototype,bean在IOC容器中可以有多个实例,getBean()时创建对象 -->
<bean class="com.ly.spring6.bean.User" scope="prototype"></bean>
11.bean的生命周期

bean的后置处理器会在生命周期的初始化前后添加额外的操作,需要实现BeanPostProcessor接口,且配置到IOC容器中,需要注意的是,bean后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有bean都会执行

创建bean的后置处理器:

package com.ly.spring6.iocxml.life;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @author 刘宇
 */
public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        try {
            System.out.println("3 bean后置处理器,初始化之前执行");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("5 bean后置处理器,初始化之后执行");
        return bean;
    }
}
<!-- bean的后置处理器要放入IOC容器才能生效 -->
<bean id="myBeanProcessor" class="com.ly.spring6.iocxml.life.MyBeanPost"/>
12.FactorBean

FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们。

将来我们整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的。

13.基于xml自动装配

使用bean标签的autowire属性设置自动装配效果

动装配方式:byType

类型匹配

byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值

若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null

若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionException

<bean id="userController" class="com.ly.spring6.iocxml.auto.controller.UserController" autowire="byType"></bean>
<bean id="userService" class="com.ly.spring6.iocxml.auto.service.UserServiceImpl" autowire="byType"></bean>
<bean id="userDao" class="com.ly.spring6.iocxml.auto.dao.UserDaoImpl"></bean>

自动装配方式:byName

byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值,名称匹配,名字要一致

<bean id="userController" class="com.ly.spring6.iocxml.auto.controller.UserController" autowire="byName"></bean>
<bean id="userService" class="com.ly.spring6.iocxml.auto.service.UserServiceImpl" autowire="byName"></bean>
<bean id="userDao" class="com.ly.spring6.iocxml.auto.dao.UserDaoImpl"></bean>

基于注解管理bean(*)

从 Java 5 开始,Java 增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。

Spring 从 2.5 版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化 Spring 的 XML 配置。

Spring 通过注解实现自动装配的步骤如下:

1.引入依赖

2.开启组件扫描

<?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-3.0.xsd
    http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启组件扫描功能-->
    <context:component-scan base-package="com.ly.spring6"></context:component-scan>
</beans>

注意:在使用 context:component-scan 元素开启自动扫描功能前,首先需要在 XML 配置的一级标签 中添加 context 相关的约束。

情况一:最基本的扫描方式

<?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-3.0.xsd
    http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启组件扫描功能-->
    <context:component-scan base-package="com.ly.spring6"></context:component-scan>
</beans>

情况二:指定要排除的组件

<context:component-scan base-package="com.atguigu.spring6">
    <!-- context:exclude-filter标签:指定排除规则 -->
    <!-- 
 		type:设置排除或包含的依据
		type="annotation",根据注解排除,expression中设置要排除的注解的全类名
		type="assignable",根据类型排除,expression中设置要排除的类型的全类名
	-->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <!--<context:exclude-filter type="assignable" expression="com.ly.spring6.controller.UserController"/>-->
</context:component-scan>

情况三:仅扫描指定组件

<context:component-scan base-package="com.atguigu" use-default-filters="false">
    <!-- context:include-filter标签:指定在原有扫描规则的基础上追加的规则 -->
    <!-- use-default-filters属性:取值false表示关闭默认扫描规则 -->
    <!-- 此时必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类 -->
    <!-- 
 		type:设置排除或包含的依据
		type="annotation",根据注解排除,expression中设置要排除的注解的全类名
		type="assignable",根据类型排除,expression中设置要排除的类型的全类名
	-->
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	<!--<context:include-filter type="assignable" expression="com.ly.spring6.controller.UserController"/>-->
</context:component-scan>

3.使用注解定义 Bean

4.依赖注入

实验一:@Autowired注入

单独使用@Autowired注解,默认根据类型装配。【默认是byType】

1.属性注入
//第一种方式 属性注入
@Autowired//根据类型找到对应对象,完成注入
private UserService userService;
@Autowired//根据类型找到对应对象,完成注入
private UserDao userDao;
2.set方法注入
private UserService userService;
@Autowired
public void setUserService(UserService userService) {
    this.userService = userService;
}
3.构造方法注入
@Autowired
public UserServiceImpl(UserDao userDao) {
    this.userDao = userDao;
}
4.形参注入
public UserController(@Autowired UserService userService) {
    this.userService = userService;
}
5.只有一个构造函数,无需写注解

6.@Autowired注解和@Qualifier注解联合

@Autowired
    @Qualifier("userDaoImpl") // 指定bean的名字
    private UserDao userDao;
总结
  • @Autowired注解可以出现在:属性上、构造方法上、构造方法的参数上、setter方法上。
  • 当带参数的构造方法只有一个,@Autowired注解可以省略。()
  • @Autowired注解默认根据类型注入。如果要根据名称注入的话,需要配合@Qualifier注解一起使用。\

实验二:Resource注入

@Resource注解也可以完成属性注入。那它和@Autowired注解有什么区别?

@Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)

@Autowired注解是Spring框架自己的。

@Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。

@Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。

@Resource注解用在属性上、setter方法上。

@Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。

1.根据名称进行注入

指定name注入

2.不指定名字,根据属性名注入
@Service
public class UserServiceImpl implements UserService {

    @Resource
    private UserDao myUserDao;

    @Override
    public void out() {
        myUserDao.print();
        System.out.println("Service层执行结束");
    }
}

@Repository("myUserDao")
public class UserDaoImpl implements UserDao {

    @Override
    public void print() {
        System.out.println("Dao层执行结束");
    }
}
3.属性名和名字都不一样,会根据类型自动注入
总结:

@Resource注解:默认byName注入,没有指定name时把属性名当做name,根据name找不到时,才会byType注入。byType注入时,某种类型的Bean只能有一个

全注解开发

全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文件。

package com.ly.spring6.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
● @author 刘宇
 */
@Configuration //配置类
@ComponentScan("com.ly.spring6")
public class SpringConfig {
}

手写ioc

回顾反射

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。

Java(二)中反射部分

实现Spring的Ioc

实现步骤

AOP-面向切面编程

代理模式

代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类,对象,方法

目标:被代理"套用"了非核心逻辑的类,对象,方法

静态代理

新建一个代理类

public class CalculatorStaticProxy implements Calculator {
    
    // 将被代理的目标对象声明为成员变量
    private Calculator target;
    
    public CalculatorStaticProxy(Calculator target) {
        this.target = target;
    }
    
    @Override
    public int add(int i, int j) {
    
        // 附加功能由代理类中的代理方法来实现
        System.out.println("[日志] add 方法开始了,参数是:" + i + "," + j);
    
        // 通过目标对象来实现核心业务逻辑
        int addResult = target.add(i, j);
    
        System.out.println("[日志] add 方法结束了,结果是:" + addResult);
    
        return addResult;
    }
}

静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿日志功能来说,将来其他地方也需要附加日志,那还得再声明更多个静态代理类,那就产生了大量重复的代码,日志功能还是分散的,没有统一管理。

提出进一步的需求:将日志功能集中到一个代理类中,将来有任何日志需求,都通过这一个代理类来实现。这就需要使用动态代理技术了。

动态代理

package com.ly.spring6.aop.example;

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

/**
 * @author 刘宇
 */
public class ProxyFactory {
    //目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    //返回代理对象
    public Object getProxy(){
        /**
         * newProxyInstance里有三个参数
         * 1.ClassLoader:加载动态生成代理类的类加载器
         * 2.Class[] interfaces:目标对象中实现的所有接口的Class类型数组
         * 3.InvocationHandler:设置代理对象实现目标对象方法的过程
         */
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        InvocationHandler invocationHandler=new InvocationHandler(){
            //第一个参数:代理对象
            //第二个参数:需要重写目标对象的方法
            //第三个参数:method方法里面参数
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {
                    System.out.println("[动态代理][日志] "+method.getName()+",参数:"+ Arrays.toString(args));
                    result = method.invoke(target, args);
                    System.out.println("[动态代理][日志] "+method.getName()+",结果:"+ result);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("[动态代理][日志] "+method.getName()+",异常:"+e.getMessage());
                } finally {
                    System.out.println("[动态代理][日志] "+method.getName()+",方法执行完毕");
                }
                return result;
            }
        };
        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}

AOP

概述

AOP(Aspect Oriented Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面向对象编程的一种补充和完善,它以通过预编译方式和运行期动态代理方式实现,在不修改源代码的情况下,给程序动态统一添加额外功能的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

相关术语

基于注解的AOP

步骤

1.引入相关依赖

2.创建目标资源 (1)接口 (2)实现类

3.创建切面类 (1)切入点 (2)通知类型

基于注解

基于xml配置文件

【Spring高手之路19——Spring AOP注解指南 - CSDN App】Spring高手之路19——Spring AOP注解指南_aop注解生效时间-CSDN博客

事务

什么是事务

什么是事务?-CSDN博客

声明式事务

声明式事务- CSDN搜索

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2199352.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux系统和数据库常用的命令2

Linux系统和数据库常用的命令2 1、两台Linux机器ssh免密登录 client端登录server端需要免密&#xff0c;只需把公钥发送到server就可&#xff0c;会在server端生成一个authorized_keys文件 # 108机器上[rootclient ~]# ssh-keygen -t rsa // 非对称算法 Generating public/…

大学生就业招聘:Spring Boot系统的设计与实践

5系统详细实现 5.1 用户模块的实现 5.1.1 求职信息管理 大学生就业招聘系统的用户可以管理自己的求职信息&#xff0c;可以对自己的求职信息添加修改删除操作。具体界面的展示如图5.1所示。 图5.1 求职信息管理界面 5.1.2 首页 用户登录可以在首页看到招聘信息展示也一些求职…

IR2110S的代替品SLM2110CG一款能提供独立的高边、低边输出驱动信号 高低边门极驱动器

SLM2110CG是一款高压、高速的功率MOSFET和IGBT驱动器&#xff0c;它提供独立的高边、低边输出驱动信号。采用专有的高压集成电路和锁存免疫CMOS技术&#xff0c;提供可靠的单芯片驱动方案。逻辑输入电平与标准CMOS或LSTTL输出兼容&#xff0c;最低支持3.3V逻辑。输出驱动器具有…

Linux——定时任务调度

crond 任务调度 基本介绍 快速入门 就会每隔一分钟执行上述命令 crond 时间规则 比如快速入门案例里的 */1 * * * * 表示每隔一分钟执行一次 5个*分别代表分时天月周 crond 应用案例 上图案例2的详细步骤截图如下&#xff1a; at 任务调度 at 定时任务就是在要求的时间只…

刷题 -哈希

面试面试经典 150 题 - 哈希 383. 赎金信 - 一个哈希表搞定 class Solution { public:bool canConstruct(string ransomNote, string magazine) {int hash[26] {0};for (auto& ch : magazine) {hash[ch - a];}for (auto& ch : ransomNote) {if (--hash[ch - a] < …

linux下创建软链接失败

最近在研究isce to stamps,在走流程的过程中,看了b站上Dr.Liu的视频和David Bakert的manual,按照manual进行了参数的设置,接着执行了make_single_reference_stack_isce命令,但是一直报错,发现这个报错还是国庆出去旅游的时候,想着在酒店把这个问题解决掉,但是每天早出晚…

Rust编程中的循环语句

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust编程与项目实战_夏天又到了的博客-CSDN博客 6.2 for 循 环 迭代次数是确定/固定的循环称为确定循环。for 循环是一个确定循环…

Ubuntu双卡训练过程中电脑总是突然重启【解决方法】

本来以为是温度过热造成的&#xff0c;发现不是&#xff0c;因为在重启的瞬间&#xff0c;gpu温度并没有特别高。 参见视频如下&#xff1a; 双卡训练过程中gpu温度监测 然后尝试了另一种方法&#xff1a; 限制gpu显卡的功率 具体操作如下&#xff1a; 先检查当前gpu功率限…

Electron构建桌面应用程序,服务于项目的自主学习记录(持续更新...

无所畏惧地面对未知&#xff0c;并将其视为成长的机会 大纲官网快速入门1.安装node.js -- 这里推荐用nvm管理2.脚手架创建3.electron 包安装到应用的开发依赖4.创建主进程(main.js)并启动项目1.创建页面2.配置main.js3.启动项目 -- 效果 进阶 -- 基于项目场景功能使用场景一&am…

SldWorks问题 2. 矩阵相关接口使用上的失误

问题 在计算三维点在图纸&#xff08;DrawingDoc&#xff09;中的位置时&#xff0c;就是算不对&#xff0c;明明就4、5行代码&#xff0c;怎么看都是很“哇塞”的&#xff0c;毫无问题的。 但结果就是不对。 那就调试一下吧&#xff0c;调试后发现生成的矩阵很不对劲&#…

Appium Device Farm安装教程

环境要求&#xff1a;Appium version ≥ 2.4.X 安装appium npm install -g appium2.11.3 如果安装提示如下问题 npm error code EEXIST npm error syscall rename npm error path /Users/wan/.npm/_cacache/tmp/d5787519 npm error dest /Users/wan/.npm/_cacache/content-…

Cpp::STL—list类的模拟实现(下)(14)

文章目录 前言一、默认生成函数构造函数析构函数 二、迭代器相关函数begin & end 三、访问容器相关函数front & back 四、插入、删除函数inserterasepush_back & pop_backpush_front & pop_front 五、其余函数sizeresizeemptyswap 总结 前言 承接上文&#xff…

数据恢复篇:适用于 Windows 操作系统的 5 大数据恢复软件

如今&#xff0c;数字空间正在快速发展。每个人都使用某种数字设备&#xff0c;如计算机、笔记本电脑、移动设备等来存储重要文档、照片、视频和其他重要文件。但事情并不总是一帆风顺。在很多情况下&#xff0c;技术会失败&#xff0c;您可能会遇到一些严重的问题&#xff0c;…

Leetcode 下一个排列

首先理解整数的字典序&#xff0c;字典序排列总是优先让“较小的”元素出现在前面。字典序的排列规则类似于字典中的单词排列方式&#xff0c;从左到右逐位比较&#xff0c;较小的数字优先出现。按照正整数元素排列的字典序&#xff0c;如果将每个排列视为一个整数值&#xff0…

Awaken Likho恶意组织利用高级网络工具对俄罗斯政府发起“猛攻”

近日&#xff0c;俄罗斯政府机构和工业实体遭遇了一场名为“ Awaken Likho ”的网络活动攻击活动。 卡巴斯基表示&#xff0c;攻击者现在更倾向于使用合法MeshCentral平台的代理&#xff0c;而不是他们之前用来获得系统远程访问权限的UltraVNC模块。这家俄罗斯网络安全公司详细…

函数信号发生器的使用方法

函数信号发生器&#xff08;Function Generator&#xff09;是电子工程师和技术人员在电路设计、测试和调试中常用的一种设备。它可以产生各种标准波形&#xff0c;如正弦波、方波、三角波等&#xff0c;以及用户自定义的任意波形。在本文中&#xff0c;我们将详细介绍函数信号…

Linux同时安装多个JDK

Linux同时安装多个JDK 一、JDK1.1、JDK的下载1.2、解压并放置目录 二、通过alias切换版本2.1、修改profile文件2.2、使用和验证 三、使用update-alternatives工具3.1、修改profile文件3.2、指定JDK版本3.3、使用和验证 四、总结 一、JDK 1.1、JDK的下载 JDK官网下载&#xff…

抖音外卖小时达服务商申请渠道开通,首选服务商推荐!

近日&#xff0c;国内头部短视频平台抖音正式宣布取消小时达业务的城市限制&#xff0c;并开启服务商的招募工作。随即&#xff0c;全国各地的商家和有意向进入本地生活赛道的创业者们都开始打听起了与抖音小时达服务商相关的各类消息&#xff0c;以抖音小时达服务商怎么申请为…

大模型生成PPT大纲优化方案:基于 nVidia NIM 平台的递归结构化生成

大模型生成PPT大纲优化方案&#xff1a;基于 nVidia NIM 平台的递归结构化生成 待解决的问题 生成PPT大纲是一种大模型在办公场景下应用的常见需求。 然而&#xff1a; 目前直接让大模型生成大纲往往是非结构化的&#xff0c;输出格式多样&#xff0c;难以统一和规范&#…

ZBrush入门使用介绍——17、FiberMesh

大家好&#xff0c;我是阿赵。   继续介绍ZBrush的使用。这次来看看FiberMesh功能。这是一个可以模仿毛发的功能。 一、 使用FiberMesh的预览功能 先准备一个模型&#xff0c;并生成多边形网格 然后按着Ctrl&#xff0c;在模型的表面画一个遮罩。 找到FiberMesh功能&#…