尚硅谷javaSpring

尚硅谷课件:

分类:尚硅谷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搜索

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值