做机械的有什么网站wordpress win8 主题下载

当前位置: 首页 > news >正文

做机械的有什么网站,wordpress win8 主题下载,高端品质网站建设,三站合一的网站怎么做教程文章目录 1. Spring 是什么#xff1f;2. IoC3. Spring Demo4. IoC 创建对象的方式 / DI 方式注入的默认参数在哪里设定? 5. Spring 配置tx:annotation-driven 用于启用基于注解的事务管理 6. Bean的作用域7. 在Spring中有三种自动装配的方式1. 在xml中显式的配置2. 在java中… 文章目录 1. Spring 是什么2. IoC3. Spring Demo4. IoC 创建对象的方式 / DI 方式注入的默认参数在哪里设定? 5. Spring 配置tx:annotation-driven 用于启用基于注解的事务管理 6. Bean的作用域7. 在Spring中有三种自动装配的方式1. 在xml中显式的配置2. 在java中显式配置3. 隐式的自动装配bean。【重要】byName 自动装配byType 自动装配 8. 注解9. applicationContext.xml与beans.xml有什么区别10. Java Config11. 横向开发 VS 纵向开发12. 代理模式13. 静态代理 VS 动态代理静态代理动态代理InvocationHandler 与 Proxy基于接口——JDK动态代理基于类——CGLIB动态代理 14. AOP核心概念实现1. 基于 xml 配置类实现2. 自定义类3. 使用注解实现 15. 静态资源过滤问题16. Spring 整合Mybatis17. 声明式事务18. spring事务传播特性参考 1. Spring 是什么 Spring就是一个轻量级的控制反转IOC和面向切面编程AOP的框架。 Spring 框架的核心特点包括 依赖注入Dependency InjectionDISpring 提供了一个容器负责管理应用程序中的对象bean以及它们之间的依赖关系。通过依赖注入开发人员可以将对象的依赖关系从代码中解耦提高了代码的灵活性和可维护性。 面向切面编程Aspect-Oriented ProgrammingAOPSpring 支持 AOP允许开发人员在应用程序中声明性地定义横切关注点cross-cutting concerns如日志记录、事务管理等并将它们与核心业务逻辑分开提高了代码的模块化和可维护性。 模块化Spring 框架被组织为多个模块每个模块都提供不同的功能如核心容器、数据访问、Web 开发、安全性等。开发人员可以根据需要选择并使用这些模块使得 Spring 框架具有高度的可定制性和灵活性。 声明式事务管理Spring 提供了声明式事务管理的支持开发人员可以通过配置简单的元数据来管理事务而无需编写复杂的事务管理代码。 面向接口编程Spring 鼓励开发人员使用接口来编程而不是直接使用实现类。这种面向接口的设计使得代码更易于扩展和维护并且使得单元测试更加容易进行。 简化企业级开发Spring 提供了许多工具和技术如 Spring MVC、Spring Boot、Spring Data 等可以帮助开发人员快速地构建企业级应用程序并且减少了开发过程中的样板代码。 2. IoC 控制反转loC(Inversion of Control)是一种设计思想DI依赖注入是实现loC的一种方法 控制反转是一种通过描述XML或注解并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器其实现方法是依赖注入Dependency Injection,DI 对象由Spring 来创建 , 管理 , 装配 !
控制反转IoC是一种软件设计原则它反转了传统应用程序中对象的创建和管理流程。在传统的应用程序中对象之间的依赖关系通常由对象自身来管理或硬编码。但在IoC容器中对象的创建和管理由容器来负责它会自动地将依赖关系注入到对象中。这种反转的控制权使得对象之间的耦合度降低更容易进行测试、维护和扩展。 在Spring框架中IoC容器负责管理应用程序中的组件例如Java类和对象。Spring的IoC容器利用依赖注入DI的机制来实现控制反转。通过依赖注入容器会在对象被创建的时候自动将其依赖的其他对象注入进来从而实现了解耦和松散耦合的目标。

  1. Spring Demo UserService.java public class UserService {public String getUserInfo() {return User information from UserService;} }UserDao.java public class UserDAO {public String getUserData() {return User data from UserDAO;} }UserController.java 依赖注入 public class UserController {private UserService userService;private UserDAO userDAO;// 通过构造函数注入 UserService 和 UserDAOpublic UserController(UserService userService, UserDAO userDAO) {this.userService userService;this.userDAO userDAO;}public String getUserInfo() {String userInfo userService.getUserInfo();String userData userDAO.getUserData();return User Info: userInfo , User Data: userData;} }applicationContext.xml 配置 Spring 容器以管理这些组件之间的依赖关系 beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd!– 配置 UserService –bean iduserService classcom.example.UserService /!– 配置 UserDAO –bean iduserDAO classcom.example.UserDAO /!– 配置 UserController并注入 UserService 和 UserDAO –bean iduserController classcom.example.UserControllerconstructor-arg refuserService /constructor-arg refuserDAO //bean/beansapplicationContext.xml / beans.xml 有三种方式编写 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd!– 第一种根据index参数下标设置 – !– bean iduserT classcom.github.subei.pojo.UserT– !– constructor-arg index0 valuesubeily——/– !– /bean–!– 第二种根据参数类型设置不建议使用 – !– bean iduserT classcom.github.subei.pojo.UserT– !– constructor-arg typejava.lang.String valuesubeily2——/– !– /bean–!– 第三种根据参数名字设置 –bean iduserT classcom.github.subei.pojo.UserT!– name指参数名 –constructor-arg namename valuesubeily3——//bean/beansMainApplication import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class MainApp {public static void main(String[] args) {// 加载 Spring 容器ApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml);// 获取 UserController beanUserController userController (UserController) context.getBean(userController);// 调用 getUserInfo 方法String userInfo userController.getUserInfo();System.out.println(userInfo);} }4. IoC 创建对象的方式 / DI 方式 构造函数注入Constructor Injection 在构造函数注入中依赖关系通过构造函数来注入。IoC容器会在创建对象时调用其构造函数并将依赖的对象作为参数传递给构造函数。这样对象在创建时就能够获得它所需要的依赖对象。 public class MyClass {private MyDependency dependency;public MyClass(MyDependency dependency) {this.dependency dependency;} }Setter方法注入Setter Injection 在Setter方法注入中依赖关系通过setter方法来注入。IoC容器会先创建对象然后调用对象的setter方法来设置依赖对象。这种方式可以使得依赖对象是可选的因为如果没有设置相应的依赖对象也能够被创建。 public class MyClass {private MyDependency dependency;public void setDependency(MyDependency dependency) {this.dependency dependency;} }或 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdbean idaddress classcom.github.subei.pojo.Addressproperty nameaddress value成都//beanbean idstudent classcom.github.subei.pojo.Student!– 第一种普通值注入value –property namename valuesubei/!– 第二种Bean注入ref –property nameaddress refaddress/!– 第三种数组注入 –property namebooksarrayvalueMybatis/valuevalueSpring/valuevalueSpringMVC/value/array/property!– 第四种list注入 –property namehobbylistvalue家里蹲/valuevalue精神萎靡/valuevalue无法沟通/value/list/property!– 第五种Map注入 –property namecardmapentry key学生证 value20201014/entry key身份证 value14253686//map/property!– 第六种set注入 –property namegamessetvalue保卫萝卜1/valuevalue保卫萝卜2/valuevalue保卫萝卜3/value/set/property!– 第七种null注入 –property namewifenull//property!– 第八种Properties注入 –property nameinfopropsprop key学号20210106/propprop key性别保密/propprop key姓名subei/prop/props/property/bean/beans3. 接口注入Interface Injection 在接口注入中对象实现一个特定的接口该接口包含一个方法用于注入依赖。IoC容器通过调用这个方法来注入依赖对象。java public interface Injectable {void injectDependency(MyDependency dependency); }public class MyClass implements Injectable {private MyDependency dependency;Overridepublic void injectDependency(MyDependency dependency) {this.dependency dependency;} }注解Annotation 使用注解方式可以更加简洁地指定依赖注入的方式。在Java中常用的注解包括Autowired、Inject等。通过在需要注入的字段或方法上添加注解IoC容器会自动进行依赖注入。 public class MyClass {Autowiredprivate MyDependency dependency; }拓展方式注入 在Spring Framework中除了使用常规的构造函数注入和Setter方法注入外还可以使用XML配置文件中的p:命名空间和c:命名空间进行属性注入。 p:命名空间
  • p:命名空间用于简化在XML配置文件中为Bean属性进行赋值。它允许您在Bean定义中直接设置属性值而无需显式调用相应的Setter方法。- 例如假设有一个名为Person的Bean具有name和age属性您可以使用p:命名空间进行注入如下所示xmlbean idperson classcom.example.Person p:nameJohn p:age30 /c:命名空间
  • c:命名空间用于在XML配置文件中为构造函数参数进行注入有参构造函数。它允许您在Bean定义中直接设置构造函数参数值。- 例如假设有一个名为Person的Bean构造函数需要name和age参数您可以使用c:命名空间进行注入如下所示xmlbean idperson classcom.example.Person c:_0John c:_130 /- 这里c:_0表示构造函数的第一个参数c:_1表示构造函数的第二个参数以此类推。注入的默认参数在哪里设定? 通过配置文件 许多IoC容器允许使用配置文件如XML、JSON、YAML等来指定默认参数。在配置文件中可以为特定的类或对象指定默认参数值。当IoC容器创建对象时如果没有显式指定参数值它将会使用配置文件中的默认值。 例如在Spring Framework中可以使用XML配置文件或者基于Java的配置类来指定默认参数值 bean idmyBean classcom.example.MyClassconstructor-arg valuedefaultParameterValue / /bean通过注解 有些IoC容器支持使用注解来指定默认参数。通过在类或方法上添加特定的注解可以指定默认参数值。 例如在Spring Framework中可以使用Value注解来指定默认参数值 Component public class MyClass {Value(${my.property:defaultValue})private String myProperty; }在这个例子中如果在配置文件中没有指定my.property的值则默认使用defaultValue。 通过代码配置 一些IoC容器支持通过编程方式来指定默认参数值。开发者可以在代码中显式地为对象设置默认参数值。 例如在Spring Framework中可以使用Java配置类来指定默认参数值 Configuration public class AppConfig {Beanpublic MyClass myClass() {MyClass myClass new MyClass();myClass.setDefaultParameterValue(defaultValue);return myClass;} }在这个例子中MyClass对象的默认参数值被显式地设置为defaultValue。
  1. Spring 配置 在Spring中配置文件通常是XML格式的可以使用一系列元素来定义和配置应用程序的组件。以下是一些常见的配置元素 bean元素 bean元素用于定义Spring容器中的bean。它包括属性如id用于唯一标识bean、class指定bean的类、scope指定bean的作用域、init-method指定bean初始化时调用的方法、destroy-method指定bean销毁时调用的方法等。例如 bean idmyBean classcom.example.MyClass scopesingletonproperty namepropertyName valuepropertyValue / /beanalias元素 alias 元素用于为现有的 bean 创建一个别名。这对于简化配置或者提供更有意义的名称很有用。例如 alias namemyBean aliasmyAlias /import元素 import 元素用于将其他 XML 配置文件导入到当前的配置文件中。这使得配置文件可以分解为更小的模块更易于管理和维护。例如 import resourceclasspath:other-config.xml /命名空间元素 Spring提供了一系列命名空间用于简化配置文件。例如context:component-scan用于扫描指定包下的类并将其注册为bean。另一个例子是tx:annotation-driven用于启用基于注解的事务管理。例如 context:component-scan base-packagecom.example / tx:annotation-driven /注释元素 Spring还支持使用注释来配置bean包括Component、Autowired、Bean等。这种方式是基于Java的配置方式的一部分通过在类上添加注释来告诉Spring容器如何处理这些类。 Component public class MyClass {// class definition }以上是Spring中常用的配置元素和方式。开发者可以根据项目的需要选择适合的配置方式。 tx:annotation-driven 用于启用基于注解的事务管理 tx:annotation-driven 是 Spring 中的一个 XML 配置元素用于启用基于注解的事务管理支持。通过在 Spring 配置文件中包含该元素Spring 容器会自动检测被 Transactional 注解标记的方法并在执行这些方法时提供事务管理支持。 具体来说tx:annotation-driven 主要做了以下几件事情 注册 TransactionInterceptor beantx:annotation-driven 在 Spring 容器中注册一个 TransactionInterceptor bean用于处理 Transactional 注解。 启用事务注解驱动它告诉 Spring 启用基于注解的事务管理支持。 配置事务管理器它会自动检测当前 Spring 上下文中的事务管理器例如 DataSourceTransactionManager 或 JpaTransactionManager并将其应用于被 Transactional 注解标记的方法。
    示例用法如下所示 beans xmlnshttp://www.springframework.org/schema/beansxmlns:txhttp://www.springframework.org/schema/txxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd!– 配置数据源 –bean iddataSource classorg.springframework.jdbc.datasource.DriverManagerDataSource!– 数据源配置 –/bean!– 配置事务管理器 –bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource //bean!– 启用基于注解的事务管理 –tx:annotation-driven /!– 其他 bean 配置 –/beans在这个示例中tx:annotation-driven 元素启用了基于注解的事务管理支持并且自动检测并使用了名为 transactionManager 的事务管理器。接下来你可以在需要事务管理的方法上使用 Transactional 注解来启用事务管理。例如 Service public class MyService {Autowiredprivate MyRepository repository;Transactionalpublic void performTransactionalOperation() {// 执行数据库操作repository.save(entity);} }这样在调用 performTransactionalOperation() 方法时Spring 会自动为其创建一个事务并在方法执行结束后根据执行情况来提交或回滚事务。
  2. Bean的作用域 在Spring Framework中Bean的作用域指的是Spring容器如何管理和创建Bean实例以及这些实例的生命周期。Spring定义了几种不同的作用域每种作用域都控制着Bean实例的创建和销毁方式以及在应用程序中的可见性。以下是Spring中常见的Bean作用域 Singleton单例 默认作用域每个Spring容器中只存在一个Bean实例。Spring容器在第一次请求该Bean时创建实例并在容器关闭时销毁实例。所有对该Bean的请求都返回同一个实例。适用于状态无关的Bean如服务类、数据访问类等。 Prototype原型 每次通过容器的getBean()方法请求时都会创建一个新的Bean实例。Spring容器不会管理Prototype作用域的Bean的生命周期也不负责销毁它们。每次请求该Bean时都会创建一个新的实例并在返回后不再管理它。适用于状态相关的Bean如HTTP请求的处理类、会话Bean等。 Request请求 每个HTTP请求都会创建一个新的Bean实例该实例仅在当前HTTP请求范围内有效。仅在Spring Web应用程序中有效在单例Bean中注入Request作用域的Bean时需要注意。Spring MVC中常用于Web应用程序中处理每个HTTP请求的控制器。 Session会话 每个HTTP会话创建一个新的Bean实例该实例在整个会话期间有效。仅在Spring Web应用程序中有效在单例Bean中注入Session作用域的Bean时需要注意。通常用于保存用户会话状态的Bean。 Application应用 在ServletContext范围内创建一个Bean实例该实例在整个应用程序的生命周期内有效。仅在Spring Web应用程序中有效在单例Bean中注入Application作用域的Bean时需要注意。通常用于在应用程序级别共享的全局配置信息或状态。 WebSocketWebSocket 每个WebSocket连接创建一个新的Bean实例该实例在WebSocket会话期间有效。用于在Spring WebSocket应用程序中保存WebSocket连接的状态。 选择适当的作用域取决于Bean的性质和在应用程序中的使用方式。默认情况下建议使用Singleton作用域除非有特定的需求需要使用其他作用域。 Beanpublic SingletonBean singletonBean() {return new SingletonBean();}// Prototype BeanBeanScope(prototype)public PrototypeBean prototypeBean() {return new PrototypeBean();}RequestScope Component public class LoginAction {// … }SessionScope Component public class UserPreferences {// … }或 bean iduser classcom.github.subei.pojo.User/!– 以下内容是等价的尽管是多余的(默认为单例作用域) –bean iduser2 classcom.github.subei.pojo.Userscopesingleton/bean iduser2 classcom.github.subei.pojo.Userscopeprototype/ 7. 在Spring中有三种自动装配的方式
  3. 在xml中显式的配置 这是最传统的方式通过在XML配置文件中使用bean元素来定义Bean并在需要注入依赖的地方使用property或constructor-arg元素来显式指定依赖的Bean。这种方式需要开发人员手动配置所有的Bean和它们之间的依赖关系不具备自动发现和连接的能力。 bean iddependencyBean classcom.example.DependencyBean / bean idmyBean classcom.example.MyBeanproperty namedependency refdependencyBean / /bean2. 在java中显式配置 使用Java Config也称为Java Configuration的方式通过在Java类中使用Configuration注解和Bean注解来声明Bean并通过Autowired注解来注入依赖关系。这种方式将Bean的定义和依赖关系配置移到了Java代码中使得配置更加类型安全并且可以利用Java语言的特性进行更灵活的配置。 Configuration public class AppConfig {Beanpublic DependencyBean dependencyBean() {return new DependencyBean();}Beanpublic MyBean myBean() {return new MyBean(dependencyBean());} }3. 隐式的自动装配bean。【重要】 Spring框架提供了自动装配机制可以通过在类的构造器、属性、或方法上使用Autowired注解来隐式指定Bean之间的依赖关系。Spring会自动在容器中查找匹配的Bean并将其注入到目标Bean中。这种方式使得开发人员可以将关注点集中在业务逻辑上而不需要过多地关注Bean之间的依赖关系从而提高了开发效率。 第一步在 beans.xml / applicationContext.xml 导入context 约束并开启注解支持 ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:aophttp://www.springframework.org/schema/aopxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/context/spring-aop.xsd!– 开启注解的支持 –context:annotation-config/bean idcat classcom.github.subei.pojo.Cat/bean iddog classcom.github.subei.pojo.Dog/bean idpeople classcom.github.subei.pojo.People//beansjava: public class MyBean {private DependencyBean dependency;Autowiredpublic MyBean(DependencyBean dependency) {this.dependency dependency;} }byName 和 byType 自动装配: byName 自动装配 在byName自动装配中Spring 容器会自动将一个 bean 的属性与另一个 bean 的名称匹配。如果一个 bean 的属性名称与另一个 bean 的名称相同则会将这个 bean 注入到该属性中。 为了启用 byName 自动装配需要在 XML 配置文件中使用 autowirebyName 属性或者在 Java 配置类中使用 Autowired 注解结合 Qualifier 注解。 Qualifier 注解: 指定一个唯一的bean对象注入 使用 byName 自动装配时确保目标 bean 的属性名称与依赖 bean 的名称匹配。 byname的时候需要保证所有bean的id唯一并且这个bean需要和自动注入的属性的set方法的值一致
    bean iddependencyBean classcom.example.DependencyBean / bean idmyBean classcom.example.MyBean autowirebyName /或者 Configuration public class AppConfig {Beanpublic DependencyBean dependencyBean() {return new DependencyBean();}BeanAutowiredpublic MyBean myBean(Qualifier(dependencyBean) DependencyBean dependency) {return new MyBean(dependency);} }byType 自动装配 在byType自动装配中Spring 容器会自动将一个 bean 的属性与另一个 bean 的类型匹配。如果一个 bean 的属性类型与另一个 bean 的类型相同则会将这个 bean 注入到该属性中。为了启用 byType 自动装配需要在 XML 配置文件中使用 autowirebyType 属性或者在 Java 配置类中使用 Autowired 注解。使用 byType 自动装配时确保目标 bean 的属性类型与依赖 bean 的类型匹配且容器中只有一个与之匹配的 bean。bytype的时候需要保证所有bean的class唯一并且这个bean需要和自动注入的属性的类型一致 bean iddependencyBean classcom.example.DependencyBean / bean idmyBean classcom.example.MyBean autowirebyType /或者 Configuration public class AppConfig {Beanpublic DependencyBean dependencyBean() {return new DependencyBean();}BeanAutowiredpublic MyBean myBean(DependencyBean dependency) {return new MyBean(dependency);} }byName中bean的名称是指 bean 的 id 吗 是的byName 自动装配中的名称指的是 bean 的 id。Spring 容器会将属性名称与其他 bean 的 id 进行匹配。 bean/ 默认使用的是byName自动装配吗 不是的默认情况下bean/ 元素并不会启用任何自动装配。你需要显式地指定 autowire 属性为 byName 或者 byType 才能启用对应的自动装配方式。 byType 中 bean 的属性类型指的是 bean 的 class 吗 是的byType 自动装配中Spring 容器会尝试查找与属性类型匹配的 bean并将其注入到对应的属性中。 Resource 和Autowired 分别使用的是 byName 还是 byType Resource 注解默认使用 byName 自动装配它会根据属性名称去查找对应的 bean。你也可以通过 name 属性指定要注入的 bean 的名称。Autowired 注解默认使用 byType 自动装配它会根据属性类型去查找对应的 bean。你也可以结合 Qualifier 注解使用 byName 自动装配或者使用 Autowired(required false) 实现可选的自动装配。 Resource 和Autowired的区别 都是用来自动装配的都可以放在属性字段上 Autowired 通过byType的方式实现而且必须要求这个对象存在 Resource默认通过byname的方式实现如果找不到名字则通过byType实现如果两个都找不到的倩况下就报错【常用】 执行顺序不同Autowired通过byType的方式实现。Resource默认通过byname的方式实现。
  4. 注解 第一步在 beans.xml / applicationContext.xml 导入context 约束并开启注解支持 !– 开启注解的支持 – context:annotation-config/ ComponentScan 用于启用组件扫描自动扫描指定包及其子包中的组件例如带有 Component、Service、Repository、Controller 等注解的类并将其注册到 Spring 容器中。 applicationContext.xml: !– 指定要扫描的包这个包下的注解就会生效 –context:component-scan base-packagecom.github.subei.pojo/或者 使用Java配置类Configuration相当于 xml 配置文件 Configuration ComponentScan(basePackages com.example) public class AppConfig {// 这里可以添加其他配置 }Component 用于标识一个类作为 Spring 组件让 Spring 自动扫描并注册为 bean。 Service 通常用于标识服务层组件类似于 Component但提供了更具体的语义。 Repository 通常用于标识数据访问层组件如 DAO它们通常用于与数据库或其他持久化机制交互。 Controller 用于标识控制器层组件通常用于处理 Web 请求。 Autowired 用于进行自动装配可以用在构造函数、setter 方法、字段或者在配置类中的方法上。Spring 将根据类型进行匹配将相应的 bean 注入到标记了 Autowired 的属性中。 Qualifier 与 Autowired 结合使用用于指定要注入的具体 bean 的名称用以解决多个候选 bean 的自动装配歧义问题。 Value 用于将外部属性值注入到 bean 的属性中可以从属性文件、环境变量等地方获取值。 Configuration 用于标识一个类为配置类通常与 Bean 注解一起使用用于定义 bean。 Bean 通常用于在配置类中定义 beanSpring 容器会根据其返回值注册一个 bean。 Scope 用于指定 bean 的作用域例如 Singleton、Prototype 等。 PostConstruct 和 PreDestroy 用于标识初始化和销毁回调方法分别在 bean 的初始化和销毁阶段执行。
  5. applicationContext.xml与beans.xml有什么区别 applicationContext.xml 和 beans.xml 是两种常见的 Spring XML 配置文件它们在用途和功能上有一些区别。 applicationContext.xml applicationContext.xml 是 Spring 应用程序上下文的配置文件通常用于配置整个应用程序的上下文环境。在 applicationContext.xml 中可以定义各种类型的 bean、组件扫描、AOP、事务管理、国际化配置等等。applicationContext.xml 可以包含多个模块或者组件的配置通常用于配置整个应用程序的所有组件。 beans.xml beans.xml 通常是用于某个特定模块或者组件的配置文件用于配置该模块或者组件所需要的 bean。在 beans.xml 中通常只包含与特定模块或者组件相关的 bean 配置。使用 beans.xml 可以将应用程序的配置模块化使得每个模块的配置都更加清晰和独立。 总的来说applicationContext.xml 是整个 Spring 应用程序的上下文配置文件用于配置应用程序中的所有组件而 beans.xml 则是针对某个特定模块或者组件的配置文件用于配置该模块或者组件所需要的 bean。在实际开发中可以根据需要选择使用其中的一个或者同时使用两者。
  6. Java Config Java配置类Configuration相当于 xml 配置文件 Configuration ComponentScan(basePackages com.example) public class AppConfig {// 这里可以添加其他配置 }导入其他配置 package com.github.subei.config;import org.springframework.context.annotation.Configuration;Configuration //代表这是一个配置类 public class SunConfig2 { }package com.github.subei.config;import com.github.subei.pojo.User; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import;// 这个也会Spring容器托管注册到容器中因为他本来就是一个Component // Configuration代表这是一个配置类就和我们之前看的beans.xml Configuration // 代表这是一个配置类 ComponentScan(com.github.subei.pojo) Import(SunConfig2.class) // 导入合并其他配置类类似于配置文件中的 inculde 标签 public class SunConfig {// 注册一个bean就相当于我们之前写的一个bean标签;// 这个方法的名字就相当bean标签中的id属性;// 这个方法的返回值就相当bean标签中的cLass属性;Beanpublic User getUser(){return new User(); // 就是返回要注入到bean的对象} }11. 横向开发 VS 纵向开发 12. 代理模式 代理模式是一种结构型设计模式其目的是通过代理对象来控制对其它对象的访问。代理对象通常充当了被代理对象的包装器或者中间人的角色从而可以在访问实际对象之前或之后执行一些额外的操作。 代理模式主要有三种形式 静态代理在编译时就已经确定代理对象和被代理对象的关系代理类与被代理类是一对一的关系。静态代理的优点是简单易懂缺点是每一个被代理的类都需要一个代理类因此扩展性不强。 动态代理在运行时动态生成代理类无需为每个被代理类编写一个代理类。Java 中的动态代理通常使用 JDK 的动态代理或者 CGLIB 等第三方库来实现。动态代理的优点是可以减少重复代码增强灵活性和可维护性。 虚拟代理延迟创建代理对象的实例直到真正需要使用它时才进行实例化。虚拟代理通常用于需要消耗大量资源或者初始化较慢的对象通过延迟加载来提升性能。
    代理模式常见的应用场景包括 远程代理在客户端和远程服务器之间创建代理对象用于隐藏真实对象的网络细节。虚拟代理延迟加载大对象例如图片、视频等资源在需要时才真正加载。安全代理控制对真实对象的访问权限例如权限验证、身份验证等。日志记录在访问真实对象前后记录日志信息用于调试或者监控。缓存代理缓存真实对象的结果避免重复计算提升性能。 代理模式可以帮助我们实现一些横切关注点cross-cutting concerns例如日志记录、事务管理等同时也可以提高代码的可维护性和可扩展性。
  7. 静态代理 VS 动态代理 静态代理 静态代理是指在编译期间就已经确定代理对象和被代理对象的关系的代理模式。在静态代理中代理类和被代理类是一对一的关系代理类充当了被代理类的包装器对外提供与被代理类相同的接口但在调用这些接口方法时可以在前后执行一些额外的操作。 静态代理的基本结构包括三个角色 抽象接口Subject定义了代理类和被代理类共同实现的接口代理类通过实现这个接口来与被代理类保持一致。 被代理类Real Subject实际执行业务逻辑的类是代理类所代理的对象。 代理类Proxy持有一个对被代理类的引用同时实现了抽象接口通过调用被代理类的方法来完成实际的业务逻辑在方法执行前后可以执行一些额外的操作如权限验证、日志记录等。
    静态代理的优点包括 可以在不修改被代理类的情况下对其进行扩展或者增强符合开闭原则。可以控制对被代理对象的访问提高系统的安全性。可以将横切关注点如日志记录、权限验证等集中处理提高代码的可维护性。 静态代理的缺点包括 每个被代理类都需要对应一个代理类如果被代理类较多会导致类的数量增加代码量增加不利于系统的维护和扩展。静态代理在编译时就已经确定了代理对象和被代理对象的关系不够灵活无法动态改变代理对象。 抽象接口 Subject其中定义了一个 request() 方法 // Subject.java public interface Subject {void request(); }实际的被代理类 RealSubject实现了 Subject 接口 // RealSubject.java public class RealSubject implements Subject {Overridepublic void request() {System.out.println(RealSubject: Handling request.);} }代理类 Proxy也实现了 Subject 接口 // Proxy.java public class Proxy implements Subject {private RealSubject realSubject;public Proxy(RealSubject realSubject) {this.realSubject realSubject;}Overridepublic void request() {// 在调用真实主题前可以执行一些额外的操作System.out.println(Proxy: Pre-processing);// 调用真实主题的方法realSubject.request();// 在调用真实主题后可以执行一些额外的操作System.out.println(Proxy: Post-processing);} }测试类来演示如何使用静态代理 // ProxyPatternDemo.java public class ProxyPatternDemo {public static void main(String[] args) {// 创建真实主题对象RealSubject realSubject new RealSubject();// 创建代理对象将真实主题对象传递给代理对象Proxy proxy new Proxy(realSubject);// 通过代理对象调用方法proxy.request();} }输出将会是 Proxy: Pre-processing RealSubject: Handling request. Proxy: Post-processing动态代理 动态代理分为两大类基于接口的动态代理基于类的动态代理。 基于接口——JDK动态代理 基于类——cglib
    基于接口的动态代理是通过 Java 标准库中的 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口实现的。它要求被代理的类必须实现一个接口代理类通过实现同样的接口并在 InvocationHandler 的实现中拦截方法调用来实现代理功能。 而基于类的动态代理则是通过第三方库实现的比如 CGLIB。它允许在不需要目标对象实现接口的情况下创建代理通过继承目标类并重写它的方法来实现代理功能。因为是基于继承所以它无法代理被 final 修饰的类和方法。 选择使用哪种类型的动态代理取决于具体的需求和场景。如果被代理的类已经实现了接口并且你希望代理类与目标类之间存在松耦合的关系那么 JDK 动态代理是一个不错的选择。但如果被代理的类没有实现接口或者你希望在代理过程中拦截对被代理类的所有方法调用包括 final 方法那么就需要使用基于类的动态代理比如 CGLIB。 InvocationHandler 与 Proxy InvocationHandler调用处理器 java.lang.reflect.InvocationHandler 接口是用于实现动态代理的关键之一。它只定义了一个方法 invoke(Object proxy, Method method, Object[] args)在代理对象上调用方法时会触发此方法的调用。在这个方法中你可以实现代理对象方法的拦截和自定义行为。invoke 方法的参数解释 proxy代理对象调用方法时会自动传递给 invoke 方法。method被调用的方法对象。args方法调用时传递的参数数组。 InvocationHandler 的实现类实际上就是在定义代理对象的行为。你可以在 invoke 方法中添加额外的逻辑比如记录日志、执行前置/后置操作等。 Proxy代理类 java.lang.reflect.Proxy 类是 JDK 提供的用于创建动态代理对象的工具类。它提供了一系列静态方法来创建代理类实例。Proxy 类的静态方法 newProxyInstance(ClassLoader loader, Class?[] interfaces, InvocationHandler h) 用于创建代理对象。 loader类加载器用于加载代理类。interfaces被代理类实现的接口数组。hInvocationHandler 对象用于处理代理对象方法的调用。 Proxy 类创建的代理对象实际上是在运行时动态生成的它实现了被代理接口并且在方法调用时会委托给传入的 InvocationHandler 实现类处理。动态代理的核心就是通过 Proxy 类来创建代理对象并且在代理对象的方法被调用时会自动触发 InvocationHandler 实现类中的 invoke 方法。 基于接口——JDK动态代理 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;// 定义接口 interface Hello {void sayHello(); }// 实现接口的被代理类 class HelloImpl implements Hello {public void sayHello() {System.out.println(Hello, world!);} }// 实现 InvocationHandler 接口的代理处理类 class MyInvocationHandler implements InvocationHandler {private Object target;public MyInvocationHandler(Object target) {this.target target;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(Before method invocation);Object result method.invoke(target, args); // 调用被代理对象的方法System.out.println(After method invocation);return result;} }public class Main {public static void main(String[] args) {// 创建被代理对象Hello hello new HelloImpl();// 创建 InvocationHandler 实现类的实例MyInvocationHandler handler new MyInvocationHandler(hello);// 使用 Proxy.newProxyInstance() 创建代理对象Hello proxyHello (Hello) Proxy.newProxyInstance(hello.getClass().getClassLoader(),hello.getClass().getInterfaces(),handler);// 通过代理对象调用方法proxyHello.sayHello();} }基于类——CGLIB动态代理 import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;// 被代理的类无需实现接口 class Hello {public void sayHello() {System.out.println(Hello, world!);} }// 实现 MethodInterceptor 接口的代理处理类 class MyMethodInterceptor implements MethodInterceptor {public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println(Before method invocation);Object result proxy.invokeSuper(obj, args); // 调用被代理对象的方法System.out.println(After method invocation);return result;} }public class Main {public static void main(String[] args) {// 创建 Enhancer 对象Enhancer enhancer new Enhancer();// 设置被代理类为父类enhancer.setSuperclass(Hello.class);// 设置回调函数enhancer.setCallback(new MyMethodInterceptor());// 创建代理对象Hello proxyHello (Hello) enhancer.create();// 通过代理对象调用方法proxyHello.sayHello();} }14. AOP AOPAspect-Oriented Programming是一种编程范式旨在通过横切关注点cross-cutting concerns的方式来解耦系统中的各个模块使得代码更加模块化、可维护和可复用。在 AOP 中横切关注点是指在应用程序中影响多个类和方法的功能需求例如日志记录、事务管理、安全性等。 AOP 通过在程序执行期间动态地将这些横切关注点与核心业务逻辑分离开来从而达到降低代码耦合度的目的。它主要通过两种方式实现 基于代理的 AOP在这种方式下AOP 框架通过动态代理为目标对象创建一个代理对象代理对象包含了额外的横切逻辑。当调用目标对象的方法时会首先执行代理对象中的横切逻辑然后再调用目标对象的方法。 基于字节码操作的 AOP在这种方式下AOP 框架通过修改目标类的字节码来插入横切逻辑实现对目标对象的增强。常见的字节码操作工具有 ASM、CGLIB 等。 核心概念 横切关注点Cross-cutting Concerns这指的是在应用程序中涉及多个模块的功能需求例如日志记录、安全性、事务管理等。横切关注点横跨应用程序的不同部分并且通常与应用程序的核心功能无关。 切面Aspect切面是 AOP 的核心组件之一用于封装横切关注点。它定义了何时何地应用横切逻辑通知以及应用哪些连接点切入点。切面将横切逻辑与应用程序的核心业务逻辑分离开来。 通知Advice通知是切面中定义的实际行为它决定了横切逻辑在何时、何地执行以及执行哪些操作。通知类型包括前置通知Before advice、后置通知After advice、返回通知After-returning advice、异常通知After-throwing advice和环绕通知Around advice。 目标Target目标是被切面影响的对象或类。它通常包含应用程序的核心业务逻辑。 代理Proxy代理是在目标对象之上创建的对象用于控制对目标对象的访问。在 AOP 中代理包含了切面所定义的横切逻辑并且在调用目标对象方法时会执行这些逻辑。 切入点Pointcut切入点用于定义横切逻辑在何处执行。它是一个表达式指示了在应用程序中哪些连接点应该被通知影响。 连接点Join Point连接点是在应用程序执行过程中可以插入横切逻辑的具体点。这些点可以是方法调用、异常抛出、字段访问等。通知可以在连接点处被执行。 实现
  8. 基于 xml 配置类实现 UserService.java package com.fatfish.aop.service;/*** author fatfish* version 1.0* date 2024/6/10 21:13/ public interface UserService {void add();void delete();void select();void update(); }UserServiceImpl.java package com.fatfish.aop.service;/** author fatfish* version 1.0* date 2024/6/10 21:14/ public class UserServiceImpl implements UserService{public void add() {System.out.println(增加了一个用户);}public void delete() {System.out.println(删除了一个用户);}public void select() {System.out.println(查询了一个用户);}public void update() {System.out.println(更新了一个用户);} }切面类 Log.java package com.fatfish.aop.log;import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;/** author fatfish* version 1.0* date 2024/6/10 21:15/public class Log implements MethodBeforeAdvice {// method:要执行的目标对象的方法// args:参数// target:目标对象public void before(Method method, Object[] args, Object target) throws Throwable {System.out.println(target.getClass().getName() 的 method.getName() 方法被执行了);} }AfterLog.java package com.fatfish.aop.log;import org.springframework.aop.AfterReturningAdvice;import java.lang.reflect.Method;/** author fatfish* version 1.0* date 2024/6/10 21:16/public class AfterLog implements AfterReturningAdvice {// returnValue:返回值// method:被调用的方法// args:被调用的方法的对象的参数// target:被调用的目标对象public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println(执行了 method.getName() target.getClass().getName() 的 返回结果为: returnValue);} }applicationContext.xml ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd!– 注册bean –bean iduserService classcom.fatfish.aop.service.UserServiceImpl/bean idlog classcom.fatfish.aop.log.Log/bean idafterLog classcom.fatfish.aop.log.AfterLog/!– 方式一:使用原生Spring API接口 –!– 配置AOP:需要导入AOP的约束 –aop:config!– 切入点:expression:表达式 , execution(要执行的位置 * * ) –aop:pointcut idpointcut expressionexecution( com.fatfish.aop.service..(..))/!– 执行环绕增加! advice-ref执行方法 , pointcut-ref切入点 –aop:advisor advice-reflog pointcut-refpointcut/aop:advisor advice-refafterLog pointcut-refpointcut//aop:config/beans 测试类 package com.fatfish.aop;import com.fatfish.aop.service.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;/*** author fatfish* version 1.0* date 2024/6/10 21:19/public class MyTest {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml);// 动态代理代理的是接口UserService userService context.getBean(userService, UserService.class);userService.select();} }结果 com.fatfish.aop.service.UserServiceImpl的select方法被执行了 查询了一个用户 执行了selectcom.fatfish.aop.service.UserServiceImpl的返回结果为:null2. 自定义类 切入类 package com.github.subei.diy;public class DiyPointCut {public void before(){System.out.println(———方法执行前———);}public void after(){System.out.println(———方法执行后———);} } applicationContext.xml ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:aophttp://www.springframework.org/schema/aopxmlns:contexthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd!– 注册bean –bean iduserService classcom.fatfish.aop.service.UserServiceImpl/bean idlog classcom.fatfish.aop.log.Log/bean idafterLog classcom.fatfish.aop.log.AfterLog/!– 方式一:使用原生Spring API接口 –!– 配置AOP:需要导入AOP的约束 –aop:config!– 切入点:expression:表达式 , execution(要执行的位置 * * ) –aop:pointcut idpointcut expressionexecution( com.fatfish.aop.service..(..))/!– 执行环绕增加! advice-ref执行方法 , pointcut-ref切入点 –aop:advisor advice-reflog pointcut-refpointcut/aop:advisor advice-refafterLog pointcut-refpointcut//aop:config!– 第二种自定义类 –bean iddiy classcom.fatfish.aop.log.DiyPointCut/aop:config!– 自定义切面ref要引用的类 –aop:aspect refdiy!– 切入点 –aop:pointcut idpoint expressionexecution(* com.fatfish.aop.service.UserServiceImpl.(..))/!– 通知 –aop:before methodbefore pointcut-refpoint /aop:after methodafter pointcut-refpoint//aop:aspect/aop:config/beans测试类与上面一致测试结果如下 com.fatfish.aop.service.UserServiceImpl的select方法被执行了 ———方法执行前——— 查询了一个用户 ———方法执行后——— 执行了selectcom.fatfish.aop.service.UserServiceImpl的返回结果为:null3. 使用注解实现 编写一个注解实现的增强类 package com.fatfish.aop.log;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before;/** author fatfish* version 1.0* date 2024/6/10 22:09/// 使用注解方式实现AOP Aspect // 标注这个类是一个切面 public class AnnotationPointCut {Before(execution( com.fatfish.aop.service.UserServiceImpl.(..)))public void before(){System.out.println(———方法执行前———);}After(execution( com.fatfish.aop.service.UserServiceImpl.(..)))public void after(){System.out.println(———方法执行后———);}// 在环绕增强中我们可以给定一个参数代表我们要获取处理切入的点Around(execution( com.fatfish.aop.service.UserServiceImpl.*(..)))public void around(ProceedingJoinPoint jp) throws Throwable {System.out.println(环绕前);Signature signature jp.getSignature();System.out.println(签名: signature); // 获得签名// 执行目标方法:proceedObject proceed jp.proceed();System.out.println(环绕后);System.out.println(proceed);} }在Spring配置文件中注册bean并增加支持注解的配置。 !– 第三种方法:使用注解方式实现 –bean idannotationPointCut classcom.fatfish.aop.log.AnnotationPointCut/!– 开启注解支持 –aop:aspectj-autoproxy/测试代码同上结果如下 22:25:34.076 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext442d9b6e 22:25:34.249 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 12 bean definitions from class path resource [applicationContext.xml] 22:25:34.265 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean org.springframework.aop.config.internalAutoProxyCreator 22:25:34.345 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean userService 22:25:34.363 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0 22:25:34.378 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#1 22:25:34.378 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean org.springframework.aop.aspectj.AspectJPointcutAdvisor#0 22:25:34.468 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean org.springframework.aop.aspectj.AspectJPointcutAdvisor#1 22:25:34.482 [main] DEBUG org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.fatfish.aop.log.AnnotationPointCut.around(org.aspectj.lang.ProceedingJoinPoint) throws java.lang.Throwable 22:25:34.482 [main] DEBUG org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.fatfish.aop.log.AnnotationPointCut.before() 22:25:34.482 [main] DEBUG org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory - Found AspectJ method: public void com.fatfish.aop.log.AnnotationPointCut.after() 22:25:34.498 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean log 22:25:34.498 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean afterLog 22:25:34.514 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean diy 22:25:34.514 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean annotationPointCut com.fatfish.aop.service.UserServiceImpl的select方法被执行了 ———方法执行前——— 环绕前 签名:void com.fatfish.aop.service.UserService.select() ———方法执行前——— 查询了一个用户 ———方法执行后——— 环绕后 null ———方法执行后——— 执行了selectcom.fatfish.aop.service.UserServiceImpl的返回结果为:nullaop:aspectj-autoproxy——说明 通过aop命名空间的aop:aspectj-autoproxy /声明自动为spring容器中那些配置aspectJ切面的bean创建代理织入切面。当然spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作但具体实现的细节已经被aop:aspectj-autoproxy /隐藏起来了 aop:aspectj-autoproxy /有一个proxy-target-class属性默认为false表示使用jdk动态代理织入增强当配为aop:aspectj-autoproxy poxy-target-class“true”/时表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false如果目标类没有声明接口则spring将自动使用CGLib动态代理。
  9. 静态资源过滤问题 在 Maven 项目中静态资源过滤问题通常指的是在构建过程中Maven 会对项目中的资源文件如文本文件、XML 文件、属性文件等进行过滤即在部署或打包之前将其中的占位符或变量替换为实际的值。这种过滤通常用于替换项目中的配置文件中的变量比如将开发环境和生产环境中的配置信息进行替换。 然而有时候 Maven 的静态资源过滤可能会导致一些问题比如 错误的变量替换Maven 可能会误将某些内容识别为变量并进行替换导致配置文件中的内容被错误地修改。文件类型不匹配Maven 可能会对不应该被过滤的文件进行了过滤导致文件内容损坏或变得不可用。过滤规则错误配置文件中的过滤规则可能不正确导致过滤效果不符预期。 要解决 Maven 静态资源过滤问题可以尝试以下方法 调整过滤规则检查 Maven 的过滤配置确保只对需要过滤的文件进行过滤且过滤规则设置正确。配置文件排除如果有些文件不需要过滤可以在 Maven 的配置中明确排除这些文件避免对其进行过滤。调整占位符如果过滤的变量与其他内容冲突考虑调整变量的占位符或替换方式确保不会误替换其他内容。使用不同的过滤方式Maven 默认使用的是基于 ${} 形式的过滤方式你可以尝试使用其他方式比如使用 符号或其他自定义的占位符。仔细检查配置文件检查被过滤的配置文件确保其中的占位符和变量使用正确不会误被替换。 buildresourcesresourcedirectorysrc/main/java/directoryincludesinclude/*.properties/includeinclude/*.xml/include/includesfilteringtrue/filtering/resource/resources/build
  10. Spring 整合Mybatis Spring 整合 MyBatis 的主要原因之一是为了简化数据访问层的开发以及利用 MyBatis 的优势来提高开发效率和灵活性。MyBatis 提供了一种将 SQL 查询映射到 Java 对象的简单方式同时还提供了灵活的 SQL 编写和参数处理功能。Spring 则提供了一个全功能的框架用于构建企业级 Java 应用程序并提供了诸如依赖注入、事务管理、AOP 等功能。将两者结合可以使开发人员更轻松地管理数据库操作、事务和数据源配置同时也能够充分利用 Spring 的各种特性和优势。 整合 MyBatis 和 Spring 的一种常见方式是使用 MyBatis-Spring 模块。这个模块提供了一些核心组件用于将 MyBatis 和 Spring 集成在一起包括 SqlSessionFactoryBean: 这个类是整合的核心。它负责创建 MyBatis 的 SqlSessionFactory 实例用于创建 SqlSession 对象从而执行 SQL 查询。 MapperScannerConfigurer: 这个类可以帮助自动扫描指定包中的 Mapper 接口并将其注册为 Spring 的 Bean使得这些 Mapper 接口可以在 Spring 中被注入和使用。 TransactionManager: MyBatis-Spring 提供了对 Spring 事务管理器的支持使得可以在 Spring 中管理 MyBatis 的事务确保事务的一致性和完整性。 SqlSessionTemplate: 这个类提供了一种将 SqlSession 和 Spring 的事务管理结合起来的方式。它可以将 SqlSession 绑定到 Spring 的事务中并确保在事务提交或回滚时正确关闭 SqlSession。
    整合 MyBatis 和 Spring 的过程通常包括以下步骤 添加依赖在项目的 Maven 或 Gradle 配置文件中添加 MyBatis 和 MyBatis-Spring 的依赖。 配置数据源在 Spring 的配置文件中配置数据源如连接池并将其注入到 MyBatis 的配置中。 配置 SqlSessionFactory使用 SqlSessionFactoryBean 配置类创建 SqlSessionFactory并将数据源等配置信息传递给它。 扫描 Mapper 接口使用 MapperScannerConfigurer 类自动扫描 Mapper 接口并将其注册为 Spring 的 Bean。 配置事务管理器将 Spring 的事务管理器配置为 MyBatis 的事务管理器以确保在 Spring 中管理 MyBatis 的事务。 使用 Mapper 接口在业务逻辑中注入并使用 Mapper 接口调用其中定义的方法执行数据库操作。
    pom.xml dependencygroupIdorg.springframework/groupIdartifactIdspring-context/artifactIdversion5.3.9/version /dependency dependencygroupIdorg.mybatis/groupIdartifactIdmybatis/artifactIdversion3.5.6/version /dependency dependencygroupIdorg.mybatis/groupIdartifactIdmybatis-spring/artifactIdversion2.0.6/version /dependency dependencygroupIdcom.h2database/groupIdartifactIdh2/artifactIdversion1.4.200/versionscopetest/scope /dependency User.java public class User {private Long id;private String name;// getters and setters } UserMapper.java public interface UserMapper {ListUser getAllUsers();User getUserById(Long id);void insertUser(User user);void updateUser(User user);void deleteUser(Long id); } UserMapper.xml ?xml version1.0 encodingUTF-8 ? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//ENhttp://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.example.mapper.UserMapperresultMap iduserResultMap typecom.example.model.Userid propertyid columnid/result propertyname columnname//resultMapselect idgetAllUsers resultMapuserResultMapSELECT * FROM users/selectselect idgetUserById resultMapuserResultMap parameterTypejava.lang.LongSELECT * FROM users WHERE id #{id}/selectinsert idinsertUser parameterTypecom.example.model.UserINSERT INTO users (id, name) VALUES (#{id}, #{name})/insertupdate idupdateUser parameterTypecom.example.model.UserUPDATE users SET name #{name} WHERE id #{id}/updatedelete iddeleteUser parameterTypejava.lang.LongDELETE FROM users WHERE id #{id}/delete /mapper applicationContext.xml ?xml version1.0 encodingUTF-8? beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:txhttp://www.springframework.org/schema/txxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd!– 数据源配置 –bean iddataSource classorg.springframework.jdbc.datasource.DriverManagerDataSourceproperty namedriverClassName valueorg.h2.Driver/property nameurl valuejdbc:h2:mem:testdb/property nameusername valuesa/property namepassword value//bean!– MyBatis SqlSessionFactory 配置 –bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBeanproperty namedataSource refdataSource/property namemapperLocations valueclasspath:com/example/mapper/.xml//bean!– Mapper 接口自动扫描 –bean classorg.mybatis.spring.mapper.MapperScannerConfigurerproperty namebasePackage valuecom.example.mapper//bean!– 事务管理器配置 –bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource//bean!– 开启注解驱动 –context:annotation-config/tx:annotation-driven//beans Demo public class Main {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml);UserMapper userMapper context.getBean(UserMapper.class);// 插入用户User user new User();user.setId(1L);user.setName(Alice);userMapper.insertUser(user);// 查询所有用户ListUser users userMapper.getAllUsers();System.out.println(All Users:);for (User u : users) {System.out.println(u.getId() : u.getName());}// 更新用户user.setName(Bob);userMapper.updateUser(user);// 查询指定用户User retrievedUser userMapper.getUserById(1L);System.out.println(Retrieved User: retrievedUser.getName());// 删除用户userMapper.deleteUser(1L);} }
  11. 声明式事务 编程式事务管理 将事务管理代码嵌到业务方法中来控制事务的提交和回滚 缺点必须在每个事务操作业务逻辑中包含额外的事务管理代码 声明式事务管理(交由容器管理事务) 一般情况下比编程式事务好用。 将事务管理代码从业务方法中分离出来以声明的方式来实现事务管理。 将事务管理作为横切关注点通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。 声明式事务是指在软件开发中使用一种声明性方式来定义事务的行为而无需显式地编写事务管理代码。通常声明式事务是通过在配置文件或注解中指定事务的属性和行为来实现的。 在Java领域中Spring框架提供了声明式事务管理的支持。通过Spring的事务管理模块开发者可以在方法或类级别声明事务属性而不必在代码中编写显式的事务管理逻辑。在Spring中常用的声明式事务管理方式包括基于XML配置和基于注解的配置两种方式。 基于XML配置的声明式事务管理通过在Spring配置文件中定义事务管理器、事务通知器以及事务的切入点来实现。开发者可以在XML配置文件中指定哪些方法需要被事务管理以及事务的传播行为、隔离级别等属性。 配置声明式事务 !– 配置声明式事务 –bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource //bean 配置好事务管理器后去配置事务的通知 !– 结合AOP实现事物的织入 –!– 配置事务的通知: –tx:advice idtxAdvice transaction-managertransactionManagertx:attributes!– 配置哪些方法使用什么样的事务,配置事务的传播特性 –tx:method nameadd propagationREQUIRED/tx:method namedelete propagationREQUIRED/tx:method nameupdate propagationREQUIRED/tx:method namesearch* propagationREQUIRED/tx:method nameget read-onlytrue/tx:method name* propagationREQUIRED//tx:attributes/tx:advice 配置AOP !– 配置事务的切入 –aop:configaop:pointcut idtxPointcut expressionexecution(* com.github.subei.mapper..(..))/aop:advisor advice-reftxAdvice pointcut-reftxPointcut//aop:config 基于注解的声明式事务管理则是通过在方法上使用Transactional注解来标记需要被事务管理的方法开发者可以在注解中指定事务的属性如传播行为、隔离级别等。这种方式简化了配置使得事务管理更加灵活和方便。 applicationContext.xml context:component-scan base-packagecom.example.service /!– 配置数据源 – bean iddataSource classorg.springframework.jdbc.datasource.DriverManagerDataSourceproperty namedriverClassName valuecom.mysql.jdbc.Driver /property nameurl valuejdbc:mysql://localhost:3306/mydb /property nameusername valueroot /property namepassword valuepassword / /bean!– 配置事务管理器 – bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource / /bean!– 开启对注解的支持 – tx:annotation-driven /UserService.java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;Service public class UserService {Autowiredprivate UserRepository userRepository;Transactionalpublic void createUser(User user) {userRepository.save(user);}Transactionalpublic void deleteUser(long userId) {userRepository.deleteById(userId);}Transactional(readOnly true)public User getUserById(long userId) {return userRepository.findById(userId).orElse(null);}// 其他方法… } 使用声明式事务管理的好处包括 简化事务管理 开发者无需编写大量的事务管理代码而是通过配置文件或注解来定义事务的行为减少了重复代码的编写。提高可维护性 通过将事务管理与业务逻辑分离代码更易于理解和维护。降低耦合性 声明式事务将事务管理从业务逻辑中解耦使得业务逻辑更加纯粹更易于单元测试和重用。灵活性 可以通过配置文件或注解来动态调整事务的行为满足不同业务场景下的需求。 18. spring事务传播特性 Spring 事务传播特性定义了在一个方法调用另一个方法时当前方法的事务如何传播给被调用方法的行为。Spring 提供了多种事务传播特性可以根据不同的需求选择合适的特性。以下是常见的 Spring 事务传播特性 PROPAGATION_REQUIRED默认 如果当前存在事务则加入该事务如果当前没有事务则创建一个新的事务。这是最常用的传播特性适用于绝大多数情况。 PROPAGATION_SUPPORTS 支持当前事务如果当前没有事务则以非事务方式执行。如果调用者在事务中则被调用方法也在该事务中如果调用者不在事务中则被调用方法以非事务方式执行。 PROPAGATION_MANDATORY 强制要求当前存在事务否则抛出异常。被调用方法必须在调用者的事务中执行否则抛出异常。 PROPAGATION_REQUIRES_NEW 创建一个新的事务并挂起当前事务如果存在。被调用方法总是在新事务中执行不受调用者事务的影响。 PROPAGATION_NOT_SUPPORTED 以非事务方式执行并挂起当前事务如果存在。被调用方法总是以非事务方式执行不受调用者事务的影响。 PROPAGATION_NEVER 以非事务方式执行如果当前存在事务则抛出异常。被调用方法不允许在任何事务中执行如果调用者在事务中则抛出异常。 PROPAGATION_NESTED 如果当前存在事务则在嵌套事务中执行如果当前没有事务则创建一个新的事务。如果调用者在事务中则被调用方法在嵌套事务中执行如果调用者不在事务中则行为类似于 PROPAGATION_REQUIRED。 这些传播特性可以在 Transactional 注解中使用例如 Transactional(propagation Propagation.REQUIRED) public void methodA() {// … }Transactional(propagation Propagation.REQUIRES_NEW) public void methodB() {// … } 使用适当的事务传播特性可以确保事务在多个方法调用之间正确地传播和管理从而保证数据的一致性和完整性。 参考 Spring学习目录(6天) - subeiLY - 博客园