-
理解Spring容器、BeanFactory和ApplicationContext初学Spring时一定会对它的容器概念有所困惑,对context应用上下文感到无法理解,我这里参考他人的博客以及自己的理解做了一些总结,主要给自己的Java学习之路做一些总结性工作,另外希望给需要帮助的人提供一些指南。下面图中【实线】为继承extends,【虚线】为实现implements。一. spring容器理解spring容器可以理解为生产对象(OBJECT)的地方,在这里容器不只是帮我们创建了对象那么简单,它负责了对象的整个生命周期--创建、装配、销毁。而这里对象的创建管理的控制权都交给了Spring容器,所以这是一种控制权的反转,称为IOC容器,而这里IOC容器不只是Spring才有,很多框架也都有该技术。二. BeanFactory和ApplicationContext之间的关系BeanFactory和ApplicationContext是Spring的两大核心接口,而其中ApplicationContext是BeanFactory的子接口。它们都可以当做Spring的容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean。在基于Spring的Java EE应用中,所有的组件都被当成Bean处理,包括数据源,Hibernate的SessionFactory、事务管理器等。生活中我们一般会把生产产品的地方称为工厂,而在这里bean对象的地方官方取名为BeanFactory,直译Bean工厂(com.springframework.beans.factory.BeanFactory),我们一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文。Spring的核心是容器,而容器并不唯一,框架本身就提供了很多个容器的实现,大概分为两种类型:一种是不常用的BeanFactory,这是最简单的容器,只能提供基本的DI功能;一种就是继承了BeanFactory后派生而来的ApplicationContext(应用上下文),它能提供更多企业级的服务,例如解析配置文本信息等等,这也是ApplicationContext实例对象最常见的应用场景。三. BeanFactory详情介绍Spring容器最基本的接口就是BeanFactory。BeanFactory负责配置、创建、管理Bean,它有一个子接口ApplicationContext,也被称为Spring上下文,容器同时还管理着Bean和Bean之间的依赖关系。spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说,DefaultListableBeanFactory 是整个spring ioc的始祖。BeanFactory结构.png接口介绍:1.BeanFactory接口: 是Spring bean容器的根接口,提供获取bean,是否包含bean,是否单例与原型,获取bean类型,bean 别名的方法 。它最主要的方法就是getBean(String beanName)。2.BeanFactory的三个子接口: * HierarchicalBeanFactory:提供父容器的访问功能 * ListableBeanFactory:提供了批量获取Bean的方法 * AutowireCapableBeanFactory:在BeanFactory基础上实现对已存在实例的管理3.ConfigurableBeanFactory:主要单例bean的注册,生成实例,以及统计单例bean4.ConfigurableListableBeanFactory:继承了上述的所有接口,增加了其他功能:比如类加载器,类型转化,属性编辑器,BeanPostProcessor,作用域,bean定义,处理bean依赖关系, bean如何销毁…5.实现类DefaultListableBeanFactory详细介绍:实现了ConfigurableListableBeanFactory,实现上述BeanFactory所有功能。它还可以注册BeanDefinition接口详细介绍请参考:揭秘BeanFactory四. ApplicationContext介绍如果说BeanFactory是Sping的心脏,那么ApplicationContext就是完整的身躯了。ApplicationContext结构图.pngApplicationContext类结构树.pngApplicationContext常用实现类作用AnnotationConfigApplicationContext从一个或多个基于java的配置类中加载上下文定义,适用于java注解的方式。ClassPathXmlApplicationContext从类路径下的一个或多个xml配置文件中加载上下文定义,适用于xml配置的方式。FileSystemXmlApplicationContext从文件系统下的一个或多个xml配置文件中加载上下文定义,也就是说系统盘符中加载xml配置文件。AnnotationConfigWebApplicationContext专门为web应用准备的,适用于注解方式。XmlWebApplicationContext从web应用下的一个或多个xml配置文件加载上下文定义,适用于xml配置方式。Spring具有非常大的灵活性,它提供了三种主要的装配机制:在XMl中进行显示配置在Java中进行显示配置隐式的bean发现机制和自动装配*组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。*自动装配(autowiring):Spring自动满足bean之间的依赖。(使用的优先性: 3>2>1)尽可能地使用自动配置的机制,显示配置越少越好。当必须使用显示配置bean的时候(如:有些源码不是由你来维护的,而当你需要为这些代码配置bean的时候),推荐使用类型安全比XML更加强大的JavaConfig。最后只有当你想要使用便利的XML命名空间,并且在JavaConfig中没有同样的实现时,才使用XML。代码示例:通过xml文件将配置加载到IOC容器中<?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"><!--若没写id,则默认为com.test.Man#0,#0为一个计数形式--><bean id="man" class="com.test.Man"></bean></beans>public class Test {public static void main(String[] args) {//加载项目中的spring配置文件到容器//ApplicationContext context = new ClassPathXmlApplicationContext("resouces/applicationContext.xml");//加载系统盘中的配置文件到容器ApplicationContext context = new FileSystemXmlApplicationContext("E:/Spring/applicationContext.xml");//从容器中获取对象实例Man man = context.getBean(Man.class);man.driveCar();}}通过java注解的方式将配置加载到IOC容器//同xml一样描述bean以及bean之间的依赖关系@Configurationpublic class ManConfig {@Beanpublic Man man() {return new Man(car());}@Beanpublic Car car() {return new QQCar();}}public class Test {public static void main(String[] args) {//从java注解的配置中加载配置到容器ApplicationContext context = new AnnotationConfigApplicationContext(ManConfig.class);//从容器中获取对象实例Man man = context.getBean(Man.class);man.driveCar();}}隐式的bean发现机制和自动装配/*** 这是一个游戏光盘的实现*///这个简单的注解表明该类回作为组件类,并告知Spring要为这个创建bean。@Componentpublic class GameDisc implements Disc{@Overridepublic void play() {System.out.println("我是马里奥游戏光盘。");}}不过,组件扫描默认是不启用的。我们还需要显示配置一下Spring,从而命令它去寻找@Component注解的类,并为其创建bean。@Configuration@ComponentScanpublic class DiscConfig {}我们在DiscConfig上加了一个@ComponentScan注解表示在Spring中开启了组件扫描,默认扫描与配置类相同的包,就可以扫描到这个GameDisc的Bean了。这就是Spring的自动装配机制。除了提供BeanFactory所支持的所有功能外ApplicationContext还有额外的功能默认初始化所有的Singleton,也可以通过配置取消预初始化。继承MessageSource,因此支持国际化。资源访问,比如访问URL和文件。事件机制。同时加载多个配置文件。以声明式方式启动并创建Spring容器。注:由于ApplicationContext会预先初始化所有的Singleton Bean,于是在系统创建前期会有较大的系统开销,但一旦ApplicationContext初始化完成,程序后面获取Singleton Bean实例时候将有较好的性能。也可以为bean设置lazy-init属性为true,即Spring容器将不会预先初始化该bean。参考文章(一部分在上述链接中,这里就不加了):BeanFactory和ApplicationContextSpring容器BeanFactory和ApplicationContext对比Spring基础篇——Spring容器和应用上下文理解ApplicationContext探究Spring 装配bean的三种方式(注解,xml,自动装配)
-
一. spring容器理解spring容器可以理解为生产对象(OBJECT)的地方,在这里容器不只是帮我们创建了对象那么简单,它负责了对象的整个生命周期--创建、装配、销毁。而这里对象的创建管理的控制权都交给了Spring容器,所以这是一种控制权的反转,称为IOC容器,而这里IOC容器不只是Spring才有,很多框架也都有该技术。二. BeanFactory和ApplicationContext之间的关系BeanFactory和ApplicationContext是Spring的两大核心接口,而其中ApplicationContext是BeanFactory的子接口。它们都可以当做Spring的容器,Spring容器是生成Bean实例的工厂,并管理容器中的Bean。在基于Spring的Java EE应用中,所有的组件都被当成Bean处理,包括数据源,Hibernate的SessionFactory、事务管理器等。生活中我们一般会把生产产品的地方称为工厂,而在这里bean对象的地方官方取名为BeanFactory,直译Bean工厂(com.springframework.beans.factory.BeanFactory),我们一般称BeanFactory为IoC容器,而称ApplicationContext为应用上下文。Spring的核心是容器,而容器并不唯一,框架本身就提供了很多个容器的实现,大概分为两种类型:一种是不常用的BeanFactory,这是最简单的容器,只能提供基本的DI功能;一种就是继承了BeanFactory后派生而来的ApplicationContext(应用上下文),它能提供更多企业级的服务,例如解析配置文本信息等等,这也是ApplicationContext实例对象最常见的应用场景。三. BeanFactory详情介绍Spring容器最基本的接口就是BeanFactory。BeanFactory负责配置、创建、管理Bean,它有一个子接口ApplicationContext,也被称为Spring上下文,容器同时还管理着Bean和Bean之间的依赖关系。spring Ioc容器的实现,从根源上是beanfactory,但真正可以作为一个可以独立使用的ioc容器还是DefaultListableBeanFactory,因此可以这么说,DefaultListableBeanFactory 是整个spring ioc的始祖。BeanFactory结构.png接口介绍:1.BeanFactory接口: 是Spring bean容器的根接口,提供获取bean,是否包含bean,是否单例与原型,获取bean类型,bean 别名的方法 。它最主要的方法就是getBean(String beanName)。2.BeanFactory的三个子接口: * HierarchicalBeanFactory:提供父容器的访问功能 * ListableBeanFactory:提供了批量获取Bean的方法 * AutowireCapableBeanFactory:在BeanFactory基础上实现对已存在实例的管理3.ConfigurableBeanFactory:主要单例bean的注册,生成实例,以及统计单例bean4.ConfigurableListableBeanFactory:继承了上述的所有接口,增加了其他功能:比如类加载器,类型转化,属性编辑器,BeanPostProcessor,作用域,bean定义,处理bean依赖关系, bean如何销毁…5.实现类DefaultListableBeanFactory详细介绍:实现了ConfigurableListableBeanFactory,实现上述BeanFactory所有功能。它还可以注册BeanDefinition接口详细介绍请参考:揭秘BeanFactory四. ApplicationContext介绍如果说BeanFactory是Sping的心脏,那么ApplicationContext就是完整的身躯了。ApplicationContext结构图.pngApplicationContext类结构树.pngApplicationContext常用实现类作用AnnotationConfigApplicationContext从一个或多个基于java的配置类中加载上下文定义,适用于java注解的方式。ClassPathXmlApplicationContext从类路径下的一个或多个xml配置文件中加载上下文定义,适用于xml配置的方式。FileSystemXmlApplicationContext从文件系统下的一个或多个xml配置文件中加载上下文定义,也就是说系统盘符中加载xml配置文件。AnnotationConfigWebApplicationContext专门为web应用准备的,适用于注解方式。XmlWebApplicationContext从web应用下的一个或多个xml配置文件加载上下文定义,适用于xml配置方式。Spring具有非常大的灵活性,它提供了三种主要的装配机制:在XMl中进行显示配置在Java中进行显示配置隐式的bean发现机制和自动装配*组件扫描(component scanning):Spring会自动发现应用上下文中所创建的bean。*自动装配(autowiring):Spring自动满足bean之间的依赖。(使用的优先性: 3>2>1)尽可能地使用自动配置的机制,显示配置越少越好。当必须使用显示配置bean的时候(如:有些源码不是由你来维护的,而当你需要为这些代码配置bean的时候),推荐使用类型安全比XML更加强大的JavaConfig。最后只有当你想要使用便利的XML命名空间,并且在JavaConfig中没有同样的实现时,才使用XML。代码示例:通过xml文件将配置加载到IOC容器中<?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"><!--若没写id,则默认为com.test.Man#0,#0为一个计数形式--><bean id="man" class="com.test.Man"></bean></beans>public class Test {public static void main(String[] args) {//加载项目中的spring配置文件到容器//ApplicationContext context = new ClassPathXmlApplicationContext("resouces/applicationContext.xml");//加载系统盘中的配置文件到容器ApplicationContext context = new FileSystemXmlApplicationContext("E:/Spring/applicationContext.xml");//从容器中获取对象实例Man man = context.getBean(Man.class);man.driveCar();}}通过java注解的方式将配置加载到IOC容器//同xml一样描述bean以及bean之间的依赖关系@Configurationpublic class ManConfig {@Beanpublic Man man() {return new Man(car());}@Beanpublic Car car() {return new QQCar();}}public class Test {public static void main(String[] args) {//从java注解的配置中加载配置到容器ApplicationContext context = new AnnotationConfigApplicationContext(ManConfig.class);//从容器中获取对象实例Man man = context.getBean(Man.class);man.driveCar();}}隐式的bean发现机制和自动装配/*** 这是一个游戏光盘的实现*///这个简单的注解表明该类回作为组件类,并告知Spring要为这个创建bean。@Componentpublic class GameDisc implements Disc{@Overridepublic void play() {System.out.println("我是马里奥游戏光盘。");}}不过,组件扫描默认是不启用的。我们还需要显示配置一下Spring,从而命令它去寻找@Component注解的类,并为其创建bean。@Configuration@ComponentScanpublic class DiscConfig {}我们在DiscConfig上加了一个@ComponentScan注解表示在Spring中开启了组件扫描,默认扫描与配置类相同的包,就可以扫描到这个GameDisc的Bean了。这就是Spring的自动装配机制。除了提供BeanFactory所支持的所有功能外ApplicationContext还有额外的功能默认初始化所有的Singleton,也可以通过配置取消预初始化。继承MessageSource,因此支持国际化。资源访问,比如访问URL和文件。事件机制。同时加载多个配置文件。以声明式方式启动并创建Spring容器。注:由于ApplicationContext会预先初始化所有的Singleton Bean,于是在系统创建前期会有较大的系统开销,但一旦ApplicationContext初始化完成,程序后面获取Singleton Bean实例时候将有较好的性能。也可以为bean设置lazy-init属性为true,即Spring容器将不会预先初始化该bean。原文链接:https://blog.csdn.net/s573626822/article/details/109599329
-
1. Spring容器1.1 容器的定义我们先看官网中的一句话:The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans.翻译下来大概就是:Spring IOC容器就是一个org.springframework.context.ApplicationContext的实例化对象容器负责了实例化,配置以及装配一个bean那么我们可以说:从代码层次来看:Spring容器就是一个实现了ApplicationContext接口的对象,从功能上来看: Spring 容器是 Spring 框架的核心,是用来管理对象的。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。1.2 容器工作方式我们直接看官网上的一张图片,如下:Spring容器通过我们提交的pojo类以及配置元数据产生一个充分配置的可以使用的系统这里说的配置元数据,实际上我们就是我们提供的XML配置文件,或者通过注解方式提供的一些配置信息2. Spring Bean2.1 Spring Bean实例化从官网上来看,主要有以下三种方法构造方法通过静态工厂方法通过实例工厂方法这三种例子,官网都有具体的演示,这里就不再贴了,我们通过自己查阅部分源码,来验证我们在官网得到的结论,然后通过debug等方式进行验证。我们再从代码的角度进行一波分析,这里我们直接定位到org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance这个方法中,具体定位步骤不再演示了,大家可以通过形如下面这段代码:ClassPathXmlApplicationContext cc =// 这里我们通过xml配置实例化一个容器new ClassPathXmlApplicationContext("classpath:application.xml");MyServiceImpl luBan = (MyServiceImpl) cc.getBean("myServiceImpl");直接main方法运行,然后在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance这个方法的入口打一个断点,如图:接下来我们对这个方法进行分析,代码如下:protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// 1.获取这个bean的class属性,确保beanDefinition中beanClass属性已经完成解析// 我们通过xml从<bean>标签中解析出来的class属性在刚刚开始的时候必定是个字符串Class<?> beanClass = resolveBeanClass(mbd, beanName);// 省略异常判断代码.....// 2.通过beanDefinition中的supplier实例化这个beanSupplier<?> instanceSupplier = mbd.getInstanceSupplier();if (instanceSupplier != null) {return obtainFromSupplier(instanceSupplier, beanName);}// 3.通过FactoryMethod实例化这个beanif (mbd.getFactoryMethodName() != null) {return instantiateUsingFactoryMethod(beanName, mbd, args);}// 4.下面这段代码都是在通过构造函数实例化这个Bean,分两种情况,一种是通过默认的无参构造,一种 是通过推断出来的构造函数boolean resolved = false;boolean autowireNecessary = false;if (args == null) {synchronized (mbd.constructorArgumentLock) {if (mbd.resolvedConstructorOrFactoryMethod != null) {resolved = true;autowireNecessary = mbd.constructorArgumentsResolved;}}}if (resolved) {if (autowireNecessary) {return autowireConstructor(beanName, mbd, null, null);}else {return instantiateBean(beanName, mbd);}}// Candidate constructors for autowiring?Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {return autowireConstructor(beanName, mbd, ctors, args);}// Preferred constructors for default construction?ctors = mbd.getPreferredConstructors();if (ctors != null) {return autowireConstructor(beanName, mbd, ctors, null);}// No special handling: simply use no-arg constructor.return instantiateBean(beanName, mbd);}我们主要关注进行实例化的几个方法:通过BeanDefinition中的instanceSupplier直接获取一个实例化的对象。这个instanceSupplier属性我本身不是特别理解,在xml中的标签以及注解的方式都没有找到方式配置这个属性。后来在org.springframework.context.support.GenericApplicationContext这个类中找到了以下两个方法经过断点测试,发现这种情况下,在实例化对象时会进入上面的supplier方法。下面是测试代码:public static void main(String[] args) {// AnnotationConfigApplicationContext是GenericApplicationContext的一个子类AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext();ac.registerBean("service", Service.class,Service::new);ac.refresh();System.out.println(ac.getBean("service"));}这个方法一般不常用,平常我们也使用不到,就不做过多探究,笔者认为,这应该是Spring提供的一种方便外部扩展的手段,让开发者能够更加灵活的实例化一个bean。接下来我们通过不同的创建bean的手段,来分别验证对象的实例化方法通过@compent,@Service等注解的方式测试代码:public class Main {public static void main(String[] args) {// 通过配置类扫描AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);System.out.println(ac.getBean(Service.class));}}@Componentpublic class Service {}可以发现,代码执行到最后一行,同时我们看代码上面的注释可以知道,当没有进行特殊的处理的时候,默认会使用无参构造函数进行对象的实例化通过普通XML的方式(同@compent注解,这里就不赘诉了)通过@Configuration注解的方式测试代码:public class Main {public static void main(String[] args) {// 通过配置类扫描AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);// 这里将测试对象换为config即可,同时记得将条件断点更改为beanName.equlas("config")System.out.println(ac.getBean(config.class));}}同样,断点也进入最后一行通过@Bean的方式测试代码:@Configuration@ComponentScan("com.dmz.official")public class Config {@Beanpublic Service service(){return new Service();}}public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext ac =new AnnotationConfigApplicationContext(Config.class);System.out.println(ac.getBean("service"));}}可以发现,通过@Bean方法创建对象时,Spring底层是通过factoryMethod的方法进行实例化对象的。Spring会在我们需要实例化的这个对象对应的BeanDefinition中记录factoryBeanName是什么(在上面的例子中factoryBeanName就是config),同时会记录这个factoryBean中创建对象的factoryMethodName是什么,最后通过factoryBeanName获取一个Bean然后反射调用factoryMethod实例化一个对象。这里我们需要注意几个概念:这里所说的通过静态工厂方式通过factoryBeanName获取一个Bean,注意,这个Bean,不是一个FactoryBean。也就是说不是一个实现了org.springframework.beans.factory.FactoryBean接口的Bean。至于什么是FactoryBean我们在后面的文章会认真分析提到了一个概念BeanDefinition,它就是Spring对自己所管理的Bean的一个抽象。不懂可以暂且跳过,后面有文章会讲到。通过静态工厂方法的方式测试代码:public static void main(String[] args) {ClassPathXmlApplicationContext cc =new ClassPathXmlApplicationContext("application.xml");System.out.println(cc.getBean("service"));}<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- <bean id="myServiceImpl" class="com.dmz.official.service.Service"/>--><!-- the factory bean, which contains a method called get() --><bean id="myFactoryBean" class="com.dmz.official.service.MyFactoryBean"><!-- inject any dependencies required by this locator bean --></bean><!-- 测试实例工厂方法创建对象--><bean id="clientService"factory-bean="myFactoryBean"factory-method="get"/><!--测试静态工厂方法创建对象--><bean id="service"class="com.dmz.official.service.MyFactoryBean"factory-method="staticGet"/></beans>可以发现,这种情况也进入了instantiateUsingFactoryMethod方法中。通过静态工厂方法这种方式特殊之处在于,包含这个静态方法的类,不需要实例化,不需要被Spring管理。Spring的调用逻辑大概是:通过<bean>标签中的class属性得到一个Class对象通过Class对象获取到对应的方法名称的Method对象最后反射调用Method.invoke(null,args)因为是静态方法,方法在执行时,不需要一个对象。通过实例工厂方法的方式测试代码(配置文件不变):public static void main(String[] args) {ClassPathXmlApplicationContext cc =new ClassPathXmlApplicationContext("application.xml");System.out.println(cc.getBean("clientService"));}还是执行的这个方法。这个方法的执行过程我断点跟踪了以后,发现跟@Bean方式执行的流程是一样的。这里也不再赘述了。到这里,这段代码我们算结合官网大致过了一遍。其实还遗留了以下几个问题:Spring是如何推断构造函数的?我们在上面验证的都是无参的构造函数,并且只提供了一个构造函数Spring是如何推断方法的?不管是静态工厂方法,还是实例工厂方法的方式,我们都只在类中提供了一个跟配置匹配的方法名,假设我们对方法进行了重载呢?要说清楚这两个问题需要比较深入的研究代码,同时进行测试。我们在官网学习过程中,暂时不去强求这类问题。这里提出来是为了在源码学习过程中,我们可以带一定目的性去阅读。实例化总结:对象实例化,只是得到一个对象,还不是一个完全的Spring中的Bean,我们实例化后的这个对象还没有完成依赖注入,没有走完一系列的声明周期,这里需要大家注意Spring官网上指明了,在Spring中实例化一个对象有三种方式:构造函数实例工厂方法静态工厂方法我自己总结如下结论:Spring通过解析我们的配置元数据,以及我们提供的类对象得到一个Beanfinition对象。通过这个对象可以实例化出一个java bean对象。主要流程如图:这篇文章到这里就结束了,主要学习了Spring官网中的1.2,1.3两小节。下篇文章,我们开始学习1.4中的知识。主要涉及到依赖注入的一些内容,也是我们Spring中非常重要的一块内容哦原文链接:https://blog.csdn.net/fedorafrog/article/details/112785956
-
一、什么是spring? spring是2003年兴起的一个轻量级的java开发框架,它是为了解决企业应用开发的复杂性而创建的。 spring是一个容器,用于降低代码间的耦合度,根据不同情况(不同代码),采用IoC(用于主业务逻辑解耦合)和AOP(用于系统级服务与主业务逻辑解耦合)两种技术进行解耦合。 上面是spring架构图,每一块代表一个jar包,例如第一块由5个jar包组成。 二、spring的特点 1.非侵入式 spring框架的API不会在业务逻辑上出现,即业务逻辑是POJO(java原生类,不需要依赖任何额外引入的jar)。由于业务逻辑中没有spring的API,所以业务逻辑可以从spring框架迅速移植到其他框架。 2.容器 spring作为一个容器,可以管理对象的生命周期、对象与对象之间的依赖关系。可以通过配置文件,来定义对象,以及设置其与其他对象的依赖关系。 3.IoC 控制反转,即实例的创建不是由调用者完成,而是由spring容器完成,并注入调用者。容器在对象初始化时不等对象请求就主动将依赖传递给它。 4.AOP 面向切面编程,是一种编程思想,是面对对象编程OOP的补充。很多框架都实现了对AOP编程思想的实现。spring也提供了面向切面编程的丰富支持,允许分离应用的业务逻辑与系统级服务(如日志和事务管理)进行开发。 我们可以把日志、安全和事务管理等服务理解成一个“切面”,以前都是直接把这些服务写到业务逻辑代码当中,这样有两点不好:(1)业务逻辑代码不纯净,不便于阅读理解。(2)这些服务是会被业务逻辑反复使用的,完全可以剥离出来做到复用。AOP就是解决这个问题的,它可以把这些服务剥离出来形成一个“切面”,然后将“切面”动态的织入到业务逻辑中,让业务逻辑能够享受到此“切面”的服务。 三、spring与IoC IoC是一种思想,指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对象控制权的转移,将程序代码本身反转到了外部容器。 IoC是一个概念,是一种思想,其实现方式多种多样。当前比较流行的实现方式有两种: (1)依赖查找(DL):容器提供调用接口,程序代码则需提供查找的路径。 (2)依赖注入(DI):不做定位查询,所有工作由容器自动完成。(但是对象不能重名)。 3.1 spring的第一个程序 首先准备好spring的jar包和spring的依赖包,下面需要的jar包都是从这里来的。 必须:spring的4个基础jar包 如果需要测试,导入junit 如果需要记录日志,导入log4j和apache-commons中的logging jar包。logging是一个适配器,它使得框架可以使用任何日志技术,而不局限于log4j等。 到这里需要的jar包就准备好了。 1)创建一个java project 2)建立服务类及其实现类 public interface SomeService { void doSome(); } import com.hnu.service.SomeService; public class SomeServiceImpl implements SomeService { @Override public void doSome() { System.out.println("执行doSome方法!"); } } 3)在src目录下建立applicationContext.xml(取什么名字都行,官方推荐这个名字)。xml文件需要约束,可以从spring官方jar包中的spring-framework-4.2.1.RELEASE\docs\spring-framework-reference\html这个文件夹下找到xsd-configuration.html这个文件,里面有spring的约束文件格式。 建立xml文件: <?xml version="1.0" encoding="UTF-8"?> <xml-body> </xml-body> 添加约束: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- bean definitions here --> </beans> 添加自动提示(补充):拷贝http://www.springframework.org/schema/beans/spring-beans.xsd,点击window->preferences->XML Catalog 点击添加,弹出如下窗口,Key type选择URI,Key填上面复制的spring-bean的约束地址http://www.springframework.org/schema/beans/spring-beans.xsd,Location选择spring官方jar包中的spring-bean约束spring-framework-4.2.1.RELEASE\schema\beans\spring-beans-4.2.xsd ,选择4.2版本的,因为我们用的spring也是4.2的。 点击确定,然后关掉xml再打开,就有自动提示了。 4)注册bean <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- bean definitions here --> <!--注册Service --> <bean id="myService" class="com.hnu.service.implSomeServiceImpl" /> </beans> 5)获取容器对象,实现注入: import org.junit.Test; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; import org.springframework.core.io.ClassPathResource; import com.hnu.service.SomeService; import com.hnu.service.impl.SomeServiceImpl; public class MyTest { @Test public void test01(){ SomeService service = new SomeServiceImpl(); service.doSome(); } @Test public void test02(){ //1.从类路径下找配置文件 ApplicationContext ac =new ClassPathXmlApplicationContext("applicationContext.xml"); //2.从项目路径下找配置文件 //ApplicationContext ac =new FileSystemXmlApplicationContext("applicationContext.xml"); //3.从指定盘符下找配置文件 //ApplicationContext ac =new FileSystemXmlApplicationContext("d:/applicationContext.xml"); SomeService service = (SomeService) ac.getBean("myService"); service.doSome(); } @Test public void test05(){ //另外一中容器BeanFactory BeanFactory bf =new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); //BeanFactory bf =new XmlBeanFactory(new FileSystemResource("applicationContext.xml")); SomeService service = (SomeService) bf.getBean("myService"); service.doSome(); } } ApplicationContext的getBean()方法是继承的BeanFactory的。 ApplicationContext和BeanFactory容器的区别: 1)ApplicationContext容器在进行初始化时,会将其中的所有的Bean(对象)进行创建 缺点:占用系统资源 优点:响应速度快 2)BeanFactory容器中的对象,在容器初始化时并不会被创建,而是在真正获取该对象时才被创建 缺点:相对来说响应速度慢 优点:不多占用系统资源 目前计算机资源越来约廉价,我们一般都习惯用空间换时间,所以一般第一种方式用的较多一点。 连接spring源码操作(补充): alt+鼠标左键点击ApplicationContext类,弹出如下窗口: 选择External location ,Encoding选择UTF-8,根据上面的提示找到spring-context-4.2.1的源码,一般在spring-framework-4.2.1.RELEASE\libs里面。点击ok即可连上源码。 Ctrl+T可以查看类或接口的继承关系,如下: Ctrl+O可以查看类或接口的结构 ———————————————— 原文链接:https://blog.csdn.net/cqf949544506/article/details/80894673
-
1. Spring是什么? Spring是一个开放源代码的设计层面框架,解决业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。 Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。 2. Spring框架特点 Spring是一个轻量级且非侵入式的开源框架 。 Spring是包含并管理应用对象的配置和生命周期的一种容器。 Spring是可以将简单的组件配置、组合成为复杂的应用的框架。 Spring通过控制反转(IoC) 促进了低耦合。 Spring提供了面向切面编程(AOP) 的丰富支持,允许通过分离应用的业务逻辑与系统级服务进行内聚性的开发。 3. Spring框架组成 Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式。 组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下: Spring Core(核心容器):核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC)模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。 Spring Context(上下文):Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。 Spring AOP(面向切片):通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。 Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。 Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。 Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。 Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。 重要拓展:Spring Boot与Spring Cloud Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务。 Spring Cloud是基于Spring Boot实现的。 Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架。 Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。 SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。 4. 控制反转(IOC) 控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转(IOC)后将对象的创建转移给第三方调用者,控制反转可认为是获得依赖对象的方式反转。 通俗来讲,以前所有东西都是由程序去进行控制创建(代码写死,直接实例化对象), 而现在是由调用者自行控制创建对象(由调用者按需求传入对象),把主动权交给了调用者,程序不用去管怎么创建,怎么实现了,它只负责提供一个接口。 4.1 Spring IOC容器 官方解释: The org.springframework.context.ApplicationContext interface represents the Spring IoC container and is responsible for instantiating, configuring, and assembling the beans. 翻译:Spring IOC容器就是一个org.springframework.context.ApplicationContext的实例化对象,容器负责了实例化,配置以及装配一个bean 从代码层次来看:Spring IOC容器就是一个实现了ApplicationContext接口的对象, 从功能上来看: Spring 容器是 Spring 框架的核心,是用来管理对象的。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。 4.1.1 Spring IOC容器如何工作 IoC是Spring框架的核心内容,可以通过使用XML配置,也可以使用注解来实现了IoC,新版本的Spring也可以零配置实现IoC。 Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离开的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。 4.2 如何实例化Bean 构造方法 通过静态工厂方法 通过实例工厂方法 简单分析下创建bean实例的方法 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { // 1.获取这个bean的class属性,确保beanDefinition中beanClass属性已经完成解析 // 我们通过xml从<bean>标签中解析出来的class属性在刚刚开始的时候必定是个字符串 Class<?> beanClass = resolveBeanClass(mbd, beanName); // 省略异常判断代码..... // 2.通过beanDefinition中的supplier实例化这个bean Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null) { return obtainFromSupplier(instanceSupplier, beanName); } // 3.通过FactoryMethod实例化这个bean if (mbd.getFactoryMethodName() != null) { return instantiateUsingFactoryMethod(beanName, mbd, args); } // 4.下面这段代码都是在通过构造函数实例化这个Bean,分两种情况,一种是通过默认的无参构造,一种是通过推断出来的构造函数 boolean resolved = false; boolean autowireNecessary = false; if (args == null) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null) { resolved = true; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { return autowireConstructor(beanName, mbd, null, null); } else { return instantiateBean(beanName, mbd); } } // Candidate constructors for autowiring? Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // Preferred constructors for default construction? ctors = mbd.getPreferredConstructors(); if (ctors != null) { return autowireConstructor(beanName, mbd, ctors, null); } // No special handling: simply use no-arg constructor. return instantiateBean(beanName, mbd); } 通过上述代码可以发现实例化bean的方法主要分为三类: 1. 通过instanceSupplier获取,这个方法一般不常用,平常我们也使用不到,就不做过多探究,笔者认为,这应该是Spring提供的一种方便外部扩展的手段,让开发者能够更加灵活的实例化一个bean。 2. FactoryMethod,通过断点调试可以发现@compent、@Service、普通XML的方式(同@compent注解)、@Configuration等方式创建bean都是走instantiateUsingFactoryMethod(beanName, mbd, args)方法,即通过工厂方法实例化bean(包括静态工厂方法和实例工厂方法)。 public static void main(String[] args) { ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("application.xml"); System.out.println(cc.getBean("service")); } <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- <bean id="myServiceImpl" class="com.dmz.official.service.Service"/>--> <!-- the factory bean, which contains a method called get() --> <bean id="myFactoryBean" class="com.dmz.official.service.MyFactoryBean"> <!-- inject any dependencies required by this locator bean --> </bean> <!-- 测试实例工厂方法创建对象--> <bean id="clientService" factory-bean="myFactoryBean" factory-method="get"/> <!--测试静态工厂方法创建对象--> <bean id="service" class="com.dmz.official.service.MyFactoryBean" factory-method="staticGet"/> </beans> 通过静态工厂方法这种方式特殊之处在于,包含这个静态方法的类,不需要实例化,不需要被Spring管理。Spring的调用逻辑大概是: 通过<bean>标签中的class属性得到一个Class对象 通过Class对象获取到对应的方法名称的Method对象 最后反射调用Method.invoke(null,args)获取bean 3. 构造方法。 4.3 实例化总结 1. 对象实例化,只是得到一个对象,还不是一个完全的Spring中的Bean,我们实例化后的这个对象还没有完成依赖注入,没有走完一系列的声明周期,这里需要大家注意。 2. Spring官网上指明了,在Spring中实例化一个对象有三种方式: 构造函数 实例工厂方法 静态工厂方法 5. 依赖注入(DI) 5.1 依赖注入概念 依赖注入(Dependency Injection,DI): 依赖 : 指Bean对象的创建依赖于容器。 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配。 5.2 依赖注入方式 依赖注入主要分为两种方式: 构造函数注入 Setter方法注入 5.3 代码测试 public class Main02 { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new // config类主要完成对类的扫描 AnnotationConfigApplicationContext(Config.class); Service service = (Service) ac.getBean("service"); service.test(); } } // setter方法注入 @Component public class Service { private LuBanService luBanService; public Service() { System.out.println("service create"); } public void test(){ System.out.println(luBanService); } // 通过autowired指定使用set方法完成注入 @Autowired public void setLuBanService(LuBanService luBanService) { System.out.println("注入luBanService by setter"); this.luBanService = luBanService; } } // 构造方法注入 @Component public class Service { private LuBanService luBanService; public Service() { System.out.println("service create by no args constructor"); } // 通过Autowired指定使用这个构造函数,否则默认会使用无参 @Autowired public Service(LuBanService luBanService) { System.out.println("注入luBanService by constructor with arg"); this.luBanService = luBanService; System.out.println("service create by constructor with arg"); } public void test(){ System.out.println(luBanService); } } @Component public class LuBanService { LuBanService(){ System.out.println("luBan create "); } } 上述代码中,@Autowired 注解加在setter 方法和属性字段上的区别: 1. 直接添加@Autowired注解到字段上,不需要提供setter方法也能完成注入。以上面的例子来说,Spring会通过反射获取到Service中luBanService这个字段,然后通过反射包的方法,Filed.set(Service,luBanService)这种方式来完成注入。 2. 将@Autowired添加到setter方法时,我们可以通过断点看一下方法的调用栈,如下: 对于这种方式来说,最终是通过Method.invoke(object,args)的方式来完成注入的,这里的method对象就是我们的setter方法。 同时采用构造注入加属性注入会怎么样呢? Spring虽然能在构造函数里完成属性注入,但是这属于实例化对象阶段做的事情,那么在后面真正进行属性注入的时候,属性注入会将构造函数注入的属性覆盖。 总结:构造函数注入和属性注入使用官方推荐: 1. 构造函数注入跟setter方法注入可以混用,对于一些强制的依赖,我们最好使用构造函数注入,对于一些可选依赖我们可以采用setter方法注入。 2. Spring团队推荐使用构造函数的方式完成注入。但是对于一些参数过长的构造函数,Spring是不推荐的。 5.3 方法注入 5.3.1 Bean的作用域 类别 说明 Singleton 在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在,Spring IoC容器中所有对象默认是单例的 Prototype 原型模式,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行new XxxBean() Request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 Session 同一个Http Session 共享一个Bean,不同的Session 使用不用Bean,仅适用于WebApplicationContext环境 5.3.2 方法注入作用 有了上面Bean的作用域基础知识之后,就能理解方法注入的作用。 @Component public class MyService { @Autowired private LuBanService luBanService; public void test(int a){ luBanService.addAndPrint(a); } } @Component // 原型对象 @Scope("prototype") public class LuBanService { int i; LuBanService() { System.out.println("luBan create "); } // 每次将当前对象的属性i+a然后打印 public void addAndPrint(int a) { i+=a; System.out.println(i); } } public class Main02 { public static void main(String[] args) { AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Config.class); MyService service = (MyService) ac.getBean("myService"); service.test(1); service.test(2); service.test(3); } } 如上述代码,我们目的是每次都获取到不同的 LuBanService 对象,然而实际是每次调用到的LuBanService是同一个对象。当然,这也很好理解,因为在依赖注入阶段我们就完成了LuBanService的注入,之后我们在调用测试方法时,不会再去进行注入,所以我们一直使用的是同一个对象。 方法注入的作用就是解决此问题,每次使用Bean时都重新去获取。 实现方式: 1. 通过注入上下文(applicationContext对象)获取Bean // 实现org.springframework.context.ApplicationContextAware接口 @Component public class MyService implements ApplicationContextAware { private ApplicationContext applicationContext; public void test(int a) { LuBanService luBanService = ((LuBanService) applicationContext.getBean("luBanService")); luBanService.addAndPrint(a); } @Override public void setApplicationContext(@Nullable ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } } // 直接注入上下文 @Component public class MyService{ @Autowired private ApplicationContext applicationContext; public void test(int a) { LuBanService luBanService = ((LuBanService) applicationContext.getBean("luBanService")); luBanService.addAndPrint(a); } } 2. 通过@LookUp的方式(也分为注解跟XML两种方式,这里只演示注解的) @Component public class MyService{ public void test(int a) { LuBanService luBanService = lookUp(); luBanService.addAndPrint(a); } @Lookup public LuBanService lookUp(){ return null; } } 3. 方法注入 之 replace-method(使用很少) 5.4 依赖注入总结 Spring中的依赖注入就是属性注入。 我们知道一个对象由两部分组成:属性+行为(方法),可以说Spring通过属性注入+方法注入的方式掌控的整个bean。 属性注入跟方法注入都是Spring提供给我们用来处理Bean之间协作关系的手段。 属性注入有两种方式:构造函数,Setter方法。 方法注入(LookUp Method跟Replace Method)需要依赖动态代理完成。 方法注入对属性注入进行了一定程度上的补充,因为属性注入的情况下,原型对象可能会失去原型的意义。 6. 自动注入 Spring可以自动注入互相协作的bean之间的依赖。自动注入有以下两个好处: 自动注入能显著的减少我们指定属性或构造参数的必要,即可以不用依赖注入的方式为类注入相关依赖对象。 自动装配可以随着对象的演化更新配置。例如,如果需要向类添加依赖项,则可以自动满足该依赖项,而不需要修改配置。因此,自动装配在开发过程中特别有用,但是当我们的代码库变的稳定时,自动装配也不会影响我们将装配方式切换到精确注入。 自动注入四种模型: 模型 解释 no 这是目前Spring默认的注入模型,也可以说默认情况下Spring是关闭自动注入,必须要我们通过setter方法或者构造函数完成依赖注入,并且Spring也不推荐修改默认配置。建议我们使用精确的方式注入依赖。 byName 这种方式,我们为了让Spring完成自动注入需要提供两个条件: 提供setter方法 如果需要注入的属性为xxx,那么setter方法命名必须是setXxx,也就是说,命名必须规范 在找不到对应名称的bean的情况下,Spring也不会报错,只是不会给我们完成注入。 byType 测试代码跟之前唯一不同的就是修改配置autowire="byType",这里我们测试以下三种异常情况: 找不到合适类型的bean,发现不报异常,同时不进行注入 找到了多个合适类型的bean,Spring会直接报错Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.dmz.official.service.DmzService' available: expected single matching bean but found 2: dmzService,dmzService2 set方法中有两个参数,切两个参数都能找到唯一一个类型符合的bean,不报异常,也不进行注入 另外需要说明的是,我在测试的过程,将set方法仅仅命名为set,像这样public void set(DmzService dmzService),这种情况下Spring也不会进行注入。 我们可以发现,对于这两种注入模型都是依赖setter方法完成注入的,并且对setter方法命名有一定要求(只要我们平常遵从代码书写规范,一般也不会踩到这些坑)。第一,不能有多个参数;第二,不能仅仅命名为set constructor 当我们使用这种注入模型时,Spring会根据构造函数查找有没有对应参数名称的bean,有的话完成注入(跟前文的byName差不多),如果根据名称没找到,那么它会再根据类型进行查找,如果根据类型还是没找到,就会报错。 自动注入的缺陷: 1. 精确注入会覆盖自动注入。并且我们不能注入基本数据类型,字符串,Class类型(这些数据的数组也不行)。而且这是Spring故意这样设计的; 2. 自动注入不如精确注入准确。而且我们在使用自动注入时,对象之间的依赖关系不明确; 3. 对于一些为Spring容器生成文档的工具,无法获取依赖关系; 4. 容器中的多个bean定义可能会与自动注入的setter方法或构造函数参数指定的类型匹配。对于数组、集合或映射实例,这可能不会产生什么问题。但是,对于期望单个值的依赖项,我们无法随意确定到底有谁进行注入。如果没有唯一的bean定义可用,则会抛出异常。 补充一些注解的知识: @Autowired 与 @Qualifier 1. @Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。 2. @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配。 3. @Qualifier不能单独使用。 @Resource 1. @Resource如有指定的name属性,先按该属性指定的name进行byName方式查找装配;其次再进行默认的byName方式进行装配。 2. 如果以上都不成功,则按byType的方式自动装配。 3. 都不成功,则报异常。 @Autowired与@Resource异同: 1. @Autowired与@Resource都可以用来装配bean。都可以写在属性上,或写在setter方法上。 2. @Autowired 默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用。 3. @Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。 4. 它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。 ———————————————— 原文链接:https://blog.csdn.net/m0_38033199/article/details/126949283
-
一、SpringBoot的介绍 Spring是一个开放源代码的设计层面框架,解决业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用。 Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。 简而言之,Spring框架为开发Java应用程序提供了全面的基础架构支持。它包含一些很好的功能,列如依赖注入和开箱即用的等模块。 Spring框架优点: Spring是一个轻量级的、非入侵式的框架。 控制反转(IOC),面向切面编程(AOP)。 支持事务的处理,对框架整合的支持。 总结:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。 这些模块可以大大缩短应用程序的开发时间。例如,在Java Web开发的早期阶段,我们需要编写大量的重复代码来将记录插入到数据源中。但是通过使用Spring JDBC模块的JDBCTemplate,我们可以将它简化为只需几个简单配置或者几行代码。 二、SpringBoot的介绍 拓展 1、Spring Boot框架基本上是Spring框架的扩展,它消除了设置Spring应用程序所需的复杂例行配置 2、学习SpringBoot需要掌握Spring与SpringMVC 它的目标和Spring的目标是一致的,为更快,更高效的开发生态系统铺平了道路。以下是Spring Boot中的一些功能: 通过starter这一个依赖,以简化构建和复杂的应用程序配置。 可以直接main函数启动,嵌入式web服务器,避免了应用程序部署的复杂性,Metrics度量,Helth check健康检查和外部化配置。 尽可能的自动化配置Spring功能。 三、Spring与SpringBoot的比较 Maven依赖 首先,让我们看一下使用Spring创建Web应用程序所需的最小依赖项: 与Spring不同,Spring Boot只需要一个依赖项来启动和运行Web应用程序: 在构建期间,所有其他依赖项将自动添加到最终归档中,如果构建项目时没有勾选该依 赖的功能在构建期间不会有该依赖需要在配置中手动添加。 Spring Boot为不同的Spring模块提供许多依赖项,比喻我们常用的: spring-boot-starter-data-jpa spring-boot-starter-security spring-boot-starter-test spring-boot-starter-web spring-boot-starter-thymeleaf ———————————————— 原文链接:https://blog.csdn.net/weixin_49983304/article/details/124643580
-
Spring和Spring Boot都是Java开发的框架,用于简化和加速Java应用程序的开发。 Spring是一个开源的应用程序框架,它提供了一个综合的编程和配置模型,用于构建Java应用程序。Spring框架提供了许多功能,如依赖注入、面向切面编程、事务管理等,它也可以与其他框架和技术进行集成,如Hibernate、MVC框架等。Spring框架需要开发人员进行大量的配置和编写XML文件。 Spring Boot是一个开源的微服务框架,它是在Spring框架的基础上构建的。Spring Boot的目标是简化Spring应用程序的配置和部署。它提供了自动配置、起步依赖和可嵌入式服务器等功能,使得开发人员能够快速地创建独立的、可部署的Spring应用程序。Spring Boot大大减少了配置的工作量,开发人员只需要少量的代码就能够创建一个功能完整的Spring应用程序。 总而言之,Spring是一个全功能的应用程序框架,适用于大型的、复杂的应用程序开发,而Spring Boot则是一个更轻量级、更简化的框架,适用于快速、简单的应用程序开发。 Spring和Spring Boot是Java开发中常用的两个框架,它们在功能和实现上存在一些区别。以下是它们之间的一些主要区别: 配置方式:在Spring中,开发人员需要手动配置大量的组件,如数据源、事务管理器、Web服务器等。相比之下,Spring Boot通过自动配置方式,可以根据classpath中的依赖关系自动配置很多组件,简化了应用程序的配置过程。 依赖管理:Spring Boot采用了“约定优于配置”的思想,提供了一系列的starter依赖。这些依赖包含了所需的依赖和默认配置,使得开发者可以快速开始一个新的项目,而Spring则需要手动管理依赖。 微服务支持:Spring Boot的设计初衷是支持微服务的快速开发。因此,它提供了很多针对微服务的功能,例如服务注册与发现、负载均衡、断路器等。而Spring则需要通过额外的组件来实现这些功能。 项目构建:Spring Boot可以使用内嵌的Tomcat或Jetty服务器,无需部署到外部服务器,可以更加方便地构建独立的可执行JAR包或WAR包。而Spring则需要部署到外部服务器。 操作简化:Spring Boot提供了极其快速和简化的操作,让Spring开发者快速上手。它提供了Spring运行的默认配置,为通用Spring项目提供了很多非功能性特性。 总的来说,Spring Boot是Spring框架的扩展,它简化了Spring应用程序的配置和开发流程,为更快、更高效的开发生态系统铺平了道路。 ———————————————— 原文链接:https://blog.csdn.net/qq_23997827/article/details/135697093
-
引言 MyBatis-Plus 是 MyBatis 的增强工具包,提供了许多便捷的功能来简化 MyBatis 的使用。在实际项目中,我们经常需要进行批量的数据操作,例如批量插入、批量更新和批量删除。本文将介绍如何在 Spring Boot 中使用 MyBatis-Plus 进行这些批量操作。 Mybatis-Plus是一个Mybatis(opens new window)的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发。 Mybatis-Plus的优势 无侵入:只做增强不做改变,引入它不会对现有工程产生影响。 损耗小:启动即会自动注入基本CURD,性能基本无损耗,直接面向对象操作。 强大的CRUD操作:内置通用Mapper、通用Service,仅仅通过少量配置即可实现单表大部分CRUD操作,更有强大的条件构造器,满足各类使用需求。 支持Lambda形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写 错。 支持主键自动生成:支持多达4种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题。 支持ActiveRecord模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作。 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )。 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用。 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询。 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、 Postgre、SQLServer 等多种数据库。 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询。 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作。 1. 准备工作 首先,确保你的 Spring Boot 项目中已经添加了 MyBatis-Plus 的依赖。在 Maven 项目中,可以在 pom.xml 文件中添加以下依赖: <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>最新版本</version> </dependency> 2. 批量插入数据 @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { public void saveBatchUsers(List<User> userList) { saveBatch(userList); } } 在上述代码中,saveBatch 方法接收一个实体列表作为参数,然后执行批量插入操作。UserMapper 是你的 MyBatis Mapper 接口,User 是你的实体类。 3. 批量更新数据 @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { public void updateBatchUsers(List<User> userList) { updateBatchById(userList); } } updateBatchById 方法同样接收一个实体列表参数,执行批量更新操作。 4. 批量删除数据 @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { public void removeUsersByIds(List<Long> userIds) { removeByIds(userIds); } } removeByIds 方法接收一个主键 ID 的列表,执行批量删除操作。 5. 总结 通过 MyBatis-Plus 提供的 saveBatch、updateBatchById 和 removeByIds 方法,我们可以非常方便地实现在 Spring Boot 项目中的批量操作数据。这些方法简化了 SQL 的编写,提高了开发效率,同时也遵循了 MyBatis-Plus 的约定大于配置的设计理念。 在实际应用中,根据业务需求和数据量,选择合适的批量操作方法可以有效提高系统性能,减少数据库交互次数。希望本文能帮助你更好地利用 MyBatis-Plus 进行批量操作数据的开发。 ———————————————— 原文链接:https://blog.csdn.net/qq_28068311/article/details/134559225
-
前言 Mybatis-Plus是一个Mybatis(opens new window)的增强工具,在Mybatis的基础上只做增强不做改变,为简化开发。 Mybatis-Plus的优势 有:无侵入:只做增强不做改变,引入它不会对现有工程产生影响。 损耗小:启动即会自动注入基本CURD,性能基本无损耗,直接面向对象操作。 强大的CRUD操作:内置通用Mapper、通用Service,仅仅通过少量配置即可实现单表大部分CRUD操作,更有强大的条件构造器,满足各类使用需求。 支持Lambda形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写 错。 支持主键自动生成:支持多达4种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题。 支持ActiveRecord模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作。 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )。 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用。 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询。 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、 Postgre、SQLServer 等多种数据库。 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询。 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作。 使用Mybatis-plus可以很方便的实现批量新增和批量修改,不仅比自己写foreach遍历方便很多,而且性能也更加优秀。但是Mybatis-plus官方提供的批量修改和批量新增都是根据id来修改的,有时候我们需求其他字段,所以就需要我们自己修改一下。 一、批量修改 在Mybatis-plus的IService接口中有updateBatchById方法,我们常用以下方法根据id批量修改数据。 @Transactional(rollbackFor = Exception.class) default boolean updateBatchById(Collection<T> entityList) { return updateBatchById(entityList, DEFAULT_BATCH_SIZE); } @Transactional(rollbackFor = Exception.class) @Override public boolean updateBatchById(Collection<T> entityList, int batchSize) { String sqlStatement = getSqlStatement(SqlMethod.UPDATE_BY_ID); return executeBatch(entityList, batchSize, (sqlSession, entity) -> { MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>(); param.put(Constants.ENTITY, entity); sqlSession.update(sqlStatement, param); }); } 但是当我们想根据其他字段批量修改数据时,该方法就无能为力了。所以我们就可以根据第二个updateBatchById方法在自己的service类里面写一个新的批量新增方法。 public boolean updateBatchByColumn(Collection<?> entityList, String idCard) { String sqlStatement = getSqlStatement(SqlMethod.UPDATE); return executeBatch(entityList, (sqlSession, entity) -> { LambdaUpdateWrapper<SysUser> updateWrapper = Wrappers.<SysUser>lambdaUpdate() .eq(SysUser::getIdCard, idCard); Map<String, Object> param = CollectionUtils.newHashMapWithExpectedSize(2); param.put(Constants.ENTITY, entity); param.put(Constants.WRAPPER, updateWrapper); sqlSession.update(sqlStatement, param); }); } 注意sqlStatement是使用的SqlMethod.UPDATE,SysUser对象是举例,使用的是若依的用户数据。 二、批量新增或修改 在Mybatis-plus的ServiceImpl 类中有一个saveOrUpdateBatch 方法用于批量新增或修改,通过CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity))根据id查询数据是否已存在,不存在新增,存在则修改,源码如下: @Transactional(rollbackFor = Exception.class) @Override public boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize) { TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass); Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!"); String keyProperty = tableInfo.getKeyProperty(); Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!"); return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, this.log, entityList, batchSize, (sqlSession, entity) -> { Object idVal = tableInfo.getPropertyValue(entity, keyProperty); return StringUtils.checkValNull(idVal) || CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_BY_ID), entity)); }, (sqlSession, entity) -> { MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>(); param.put(Constants.ENTITY, entity); sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param); }); } 最终调用的是SqlHelper.saveOrUpdateBatch方法,该方法第六个参数是BiPredicate,这就是用于判断数据库中数据是否存在的关键,所以我们需要修改这个函数式接口,修改为根据其他条件查询数据库。该方法的第七个参数是BiConsumer,该函数式接口用于修改数据,如果不想根据id修改数据,可以参考第一部门进行修改。 @Transactional(rollbackFor = Exception.class) public boolean saveOrUpdateBatchByColumn(Collection<?> entityList, String idCard) { return SqlHelper.saveOrUpdateBatch(this.entityClass, this.mapperClass, super.log, entityList, DEFAULT_BATCH_SIZE, (sqlSession, entity) -> { LambdaQueryWrapper<SysUser> queryWrapper = Wrappers.<SysUser>lambdaQuery() .eq(SysUser::getIdCard, idCard); Map<String, Object> map = CollectionUtils.newHashMapWithExpectedSize(1); map.put(Constants.WRAPPER, queryWrapper); return CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_LIST), map)); }, (sqlSession, entity) -> { Map<String, Object> param = CollectionUtils.newHashMapWithExpectedSize(2); param.put(Constants.ENTITY, entity); sqlSession.update(getSqlStatement(SqlMethod.UPDATE_BY_ID), param); }); } 三、不使用Mybatis-plus进行批量操作 有时候项目里没有引用Mybatis-plus,但是也想进行批量操作,数据量大了后foreach循环会影响性能。所以可以参考Mybatis-plus的批量操作,编写在mybatis环境下的批量操作,代码如下: @Component public class MybatisBatchUtils { private static final int BATCH_SIZE = 1000; @Autowired private SqlSessionFactory sqlSessionFactory; public <T,U,R> boolean batchUpdateOrInsert(List<T> data, Class<U> mapperClass, BiFunction<T,U,R> function) { int i = 1; SqlSession batchSqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); try { U mapper = batchSqlSession.getMapper(mapperClass); int size = data.size(); for (T element : data) { function.apply(element, mapper); if ((i % BATCH_SIZE == 0) || i == size) { batchSqlSession.flushStatements(); } i++; } // 非事务环境下强制commit,事务情况下该commit相当于无效 batchSqlSession.commit(!TransactionSynchronizationManager.isSynchronizationActive()); return true; } catch (Exception e) { batchSqlSession.rollback(); throw new RuntimeException(e); } finally { batchSqlSession.close(); } } } 写在最后的话 Mybatis-plus真好用,少写好多代码。有些不太适用的方法,也可以很简单在官方的基础上进行扩展。 ———————————————— 原文链接:https://blog.csdn.net/WayneLee0809/article/details/126424482
-
springboot 配置文件里部分配置未生效最近用springboot搭了个项目,上线过段时间就会出现卡死,猜测是数据库连接池的连接被占满,用的连接池是druid,于是给项目加上了一个数据库连接池监控。代码如下:@Configuration public class DruidConfiguration { /** * * 注册一个StatViewServlet * * @return * */ @Bean public ServletRegistrationBean DruidStatViewServle2() { // org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册. ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); // 添加初始化参数:initParams // 白名单: // servletRegistrationBean.addInitParameter("allow", "127.0.0.1"); // IP黑名单 (存在共同时,deny优先于allow) : 如果满足deny的话提示:Sorry, you are not // permitted to view this page. // servletRegistrationBean.addInitParameter("deny", "192.168.1.73"); // 登录查看信息的账号密码. servletRegistrationBean.addInitParameter("loginUsername", "admin"); servletRegistrationBean.addInitParameter("loginPassword", "admin"); // 是否能够重置数据. servletRegistrationBean.addInitParameter("resetEnable", "false"); return servletRegistrationBean; } /** * * 注册一个:filterRegistrationBean * * @return * */ @Bean public FilterRegistrationBean druidStatFilter2() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter()); // 添加过滤规则. filterRegistrationBean.addUrlPatterns("/*"); // 添加不需要忽略的格式信息. filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid2/*"); return filterRegistrationBean; } }于是重启项目,进入监控页面发现与配置文件里面的部分配置对应不上,当时也没在意,以为是显示的默认配置。过阵子又卡死了,发现等待获取连接的线程数有10来个,果然和前面预料到的一样。于是在配置文件里面各种改数据库连接池的配置。但,并没有什么卵用,因为项目根本就没有读取到这些配置,这个问题,网上也没能找到类似的文章和解决方案,到现在也没有发现问题出现在哪儿,最后的解决办法是将配置文件里面关于数据库的配置全都注释掉,加上了一个java类来配置代码如下:/** * druid数据连接池配置 * @author win 10 * */ @Configuration public class DatasourceConfig { @Bean public DruidDataSource druidDataSource() { //Druid 数据源配置 DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://127.0.0.1/autoorder?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true"); dataSource.setUsername("root"); dataSource.setPassword("root"); //初始连接数(默认值0) dataSource.setInitialSize(3); //最小连接数(默认值0) dataSource.setMinIdle(1); //最大连接数(默认值8,注意"maxIdle"这个属性已经弃用) dataSource.setMaxActive(20); dataSource.setMaxWait(30000); try { dataSource.setFilters("stat,wall,slf4j"); } catch (SQLException e) { e.printStackTrace(); } dataSource.setTestWhileIdle(true); dataSource.setValidationQuery("SELECT 1"); dataSource.setTimeBetweenEvictionRunsMillis(60000); dataSource.setMinEvictableIdleTimeMillis(30000); dataSource.setTestOnBorrow(true); dataSource.setTestOnReturn(false); return dataSource; } }重启项目进入发现配置is working!卡死的问题解决,但是还是未能找到为什么通过resource里面的配置文件部分配置不生效的原因。贴出配置文件:# 服务启动端口 server.port=8776 #定时器开关 server.scheduler.syncorder=false server.scheduler.xepnr=false # 运维管理相关参数 timeout.host=5000 timeout.project=5000 #spring.http.encoding.force=true #spring.http.encoding.charset=UTF-8 #spring.http.encoding.enabled=true #server.tomcat.uri-encoding=UTF-8 spring.thymeleaf.content-type=text/html spring.thymeleaf.cache=false spring.thymeleaf.mode=LEGACYHTML5 # jdbc_config datasource #spring.datasource.url=jdbc:mysql://127.0.0.1:3306/autoorder?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true #spring.datasource.username=root #spring.datasource.password=root #spring.datasource.driver-class-name=com.mysql.jdbc.Driver #spring.datasource.type=com.alibaba.druid.pool.DruidDataSource #spring.datasource.maxActive=20 #spring.datasource.initialSize=1 #spring.datasource.minIdle=3 #spring.datasource.maxWait=20000 #连接空闲时长,超过时则会检查是否可用,与test-while-idle搭配 #spring.datasource.timeBetweenEvictionRunsMillis=60000 #spring.datasource.minEvictableIdleTimeMillis=300000 #连接空闲时检查是否可用 #spring.datasource.testWhileIdle=true #每次获取连接时 检查是否可用 #spring.datasource.testOnBorrow=true #每次归还连接时 检查是否可用 #spring.datasource.testOnReturn=fasle #缓存游标是否开启 #spring.datasource.poolPreparedStatements=false #spring.datasource.maxPoolPreparedStatementPerConnectionSize=20 # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙 #spring.datasource.filters=stat,wall,slf4j #验证数据库连接的有效性的sql #spring.datasource.validationQuery=SELECT 1 #开启连接回收机制 #spring.datasource.removeAbandoned=true #单位 s #spring.datasource.removeAbandonedTimeout=180 #spring.datasource.timeBetweenEvictionRunsMillis=300000 # mybatis_config mybatis.mapper-locations= classpath:org/jc/db/mapper/*Mapper.xml mybatis.typeAliasesPackage= org.jc.db.entity #主键类型 0:"数据库ID自增", 1:"用户输入ID",2:"全局唯一ID (数字类型唯一ID)", 3:"全局唯一ID UUID"; global-config.id-type=0 ##字段策略 0:"忽略判断",1:"非 NULL 判断"),2:"非空判断" field-strategy= 2 #驼峰下划线转换 db-column-underline= true #刷新mapper 调试神器 global-config.refresh-mapper= true #数据库大写下划线转换 #capital-mode: true #序列接口实现类配置 #key-generator: com.baomidou.springboot.xxx #逻辑删除配置 #logic-delete-value: 0 #logic-not-delete-value: 1 #自定义填充策略接口实现 #meta-object-handler: com.baomidou.springboot.xxx #自定义SQL注入器 #sql-injector: com.baomidou.springboot.xxx ## log_config DEBUG ERROR INFO WARN #logging.level.root=info ##logging.level.io.z77z.dao= DEBUG #logging.file= ./logs/express_interf.log #logging.pattern.console= %d{yyyy/MM/dd-HH:mm:ss} [%thread] %-5level %logger- %msg%n #logging.pattern.file= %d{yyyy/MM/dd-HH:mm} [%thread] %-5level %logger- %msg%n spring.http.multipart.maxFileSize=100Mb spring.http.multipart.maxRequestSize=200Mb有看到的小伙伴知道这个问题所在的欢迎指点一二。记录一次创建springboot 配置文件不生效的坑使用idea自动生成了一个springboot项目。把application.properties改成了application.yml文件。打包成jar包运行。神奇的事情发生了,设置的端口不生效。解决:1.自己把yml文件改回properties文件。运行,仍旧不生效2.上网百度。各种方案。然后还是不行。3.突发奇想,因为我创建的项目是只需要一个五分钟循环执行的任务,所以我没导入web的maven。故导入。 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>问题解决!!!!以上为个人经验,希望能给大家一个参考。原文链接:https://www.easck.com/cos/2021/0812/867820.shtml
-
[问题求助] FusionInsight_HD_8.2.0.1产品,在Flink SQL客户端中select 'hello'报错KeeperErrorCode = ConnectionLoss for /flink_base/flinkflinkSQL client中select 还是报错的,请帮忙指点下,哪里有问题?谢谢org.apache.flink.shaded.zookeeper3.org.apache.zookeeper.KeeperException$SessionClosedRequireAuthException: KeeperErrorCode = Session closed because client failed to authenticate for /flink_base/flink或者org.apache.flink.shaded.zookeeper3.org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /flink_base/flinkzookeeper已经启动,192.168.0.82:24002 ,而且zookeeper中的ACL权限已经设置,但是在设置配额失败[zk: 192.168.0.82:24002(CONNECTED) 5] setquota -n 1000000 /flink_base/flink Insufficient permission : /flink_base/flink tail -f /home/dmp/app/ficlient/Flink/flink/log/flink-root-sql-client-192-168-0-85.log 中的日志如下flink-conf.yaml中的全部配置如下akka.ask.timeout: 120 s akka.client-socket-worker-pool.pool-size-factor: 1.0 akka.client-socket-worker-pool.pool-size-max: 2 akka.client-socket-worker-pool.pool-size-min: 1 akka.framesize: 10485760b akka.log.lifecycle.events: false akka.lookup.timeout: 30 s akka.server-socket-worker-pool.pool-size-factor: 1.0 akka.server-socket-worker-pool.pool-size-max: 2 akka.server-socket-worker-pool.pool-size-min: 1 akka.ssl.enabled: true akka.startup-timeout: 10 s akka.tcp.timeout: 60 s akka.throughput: 15 blob.fetch.backlog: 1000 blob.fetch.num-concurrent: 50 blob.fetch.retries: 50 blob.server.port: 32456-32520 blob.service.ssl.enabled: true classloader.check-leaked-classloader: false classloader.resolve-order: child-first client.rpc.port: 32651-32720 client.timeout: 120 s compiler.delimited-informat.max-line-samples: 10 compiler.delimited-informat.max-sample-len: 2097152 compiler.delimited-informat.min-line-samples: 2 env.hadoop.conf.dir: /home/dmp/app/ficlient/Flink/flink/conf env.java.opts.client: -Djava.io.tmpdir=/home/dmp/app/ficlient/Flink/tmp env.java.opts.jobmanager: -Djava.security.krb5.conf=/opt/huawei/Bigdata/common/runtime/krb5.conf -Djava.io.tmpdir=${PWD}/tmp -Des.security.indication=true env.java.opts.taskmanager: -Djava.security.krb5.conf=/opt/huawei/Bigdata/common/runtime/krb5.conf -Djava.io.tmpdir=${PWD}/tmp -Des.security.indication=true env.java.opts: -Xloggc:<LOG_DIR>/gc.log -XX:+PrintGCDetails -XX:-OmitStackTraceInFastThrow -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=20 -XX:GCLogFileSize=20M -Djdk.tls.ephemeralDHKeySize=3072 -Djava.library.path=${HADOOP_COMMON_HOME}/lib/native -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false -Dbeetle.application.home.path=/opt/huawei/Bigdata/common/runtime/security/config -Dwcc.configuration.path=/opt/huawei/Bigdata/common/runtime/security/config -Dscc.configuration.path=/opt/huawei/Bigdata/common/runtime/securityforscc/config -Dscc.bigdata.common=/opt/huawei/Bigdata/common/runtime env.yarn.conf.dir: /home/dmp/app/ficlient/Flink/flink/conf flink.security.enable: true flinkserver.alarm.cert.skip: true flinkserver.host.ip: fs.output.always-create-directory: false fs.overwrite-files: false heartbeat.interval: 10000 heartbeat.timeout: 120000 high-availability.job.delay: 10 s high-availability.storageDir: hdfs://hacluster/flink/recovery high-availability.zookeeper.client.acl: creator high-availability.zookeeper.client.connection-timeout: 90000 high-availability.zookeeper.client.max-retry-attempts: 5 high-availability.zookeeper.client.retry-wait: 5000 high-availability.zookeeper.client.session-timeout: 90000 high-availability.zookeeper.client.tolerate-suspended-connections: true high-availability.zookeeper.path.root: /flink high-availability.zookeeper.path.under.quota: /flink_base high-availability.zookeeper.quorum: 192.168.0.82:24002,192.168.0.81:24002,192.168.0.80:24002 high-availability.zookeeper.quota.enabled: true high-availability: zookeeper job.alarm.enable: true jobmanager.heap.size: 1024mb jobmanager.web.403-redirect-url: https://192.168.0.82:28443/web/pages/error/403.html jobmanager.web.404-redirect-url: https://192.168.0.82:28443/web/pages/error/404.html jobmanager.web.415-redirect-url: https://192.168.0.82:28443/web/pages/error/415.html jobmanager.web.500-redirect-url: https://192.168.0.82:28443/web/pages/error/500.html jobmanager.web.access-control-allow-origin: * jobmanager.web.accesslog.enable: true jobmanager.web.allow-access-address: * jobmanager.web.backpressure.cleanup-interval: 600000 jobmanager.web.backpressure.delay-between-samples: 50 jobmanager.web.backpressure.num-samples: 100 jobmanager.web.backpressure.refresh-interval: 60000 jobmanager.web.cache-directive: no-store jobmanager.web.checkpoints.disable: false jobmanager.web.checkpoints.history: 10 jobmanager.web.expires-time: 0 jobmanager.web.history: 5 jobmanager.web.logout-timer: 600000 jobmanager.web.pragma-value: no-cache jobmanager.web.refresh-interval: 3000 jobmanager.web.ssl.enabled: false jobmanager.web.x-frame-options: DENY library-cache-manager.cleanup.interval: 3600 metrics.internal.query-service.port: 28844-28943 metrics.reporter.alarm.factory.class: com.huawei.mrs.flink.alarm.FlinkAlarmReporterFactory metrics.reporter.alarm.interval: 30 s metrics.reporter.alarm.job.alarm.checkpoint.consecutive.failures.num: 5 metrics.reporter.alarm.job.alarm.failure.restart.rate: 80 metrics.reporter.alarm.job.alarm.task.backpressure.duration: 180 s metrics.reporter: alarm nettyconnector.message.delimiter: $_ nettyconnector.registerserver.topic.storage: /flink/nettyconnector nettyconnector.sinkserver.port.range: 28444-28843 nettyconnector.ssl.enabled: false parallelism.default: 1 query.client.network-threads: 0 query.proxy.network-threads: 0 query.proxy.ports: 32541-32560 query.proxy.query-threads: 0 query.server.network-threads: 0 query.server.ports: 32521-32540 query.server.query-threads: 0 resourcemanager.taskmanager-timeout: 300000 rest.await-leader-timeout: 30000 rest.bind-port: 32261-32325 rest.client.max-content-length: 104857600 rest.connection-timeout: 15000 rest.idleness-timeout: 300000 rest.retry.delay: 3000 rest.retry.max-attempts: 20 rest.server.max-content-length: 104857600 rest.server.numThreads: 4 restart-strategy.failure-rate.delay: 10 s restart-strategy.failure-rate.failure-rate-interval: 60 s restart-strategy.failure-rate.max-failures-per-interval: 1 restart-strategy.fixed-delay.attempts: 3 restart-strategy.fixed-delay.delay: 10 s restart-strategy: none security.cookie: 9477298cd52a3e409ed0bc570bdc795179fcc7c301a1225e22f47fe0a3db47c2 security.enable: true security.kerberos.login.contexts: Client,KafkaClient security.kerberos.login.keytab: security.kerberos.login.principal: security.kerberos.login.use-ticket-cache: true security.networkwide.listen.restrict: true security.ssl.algorithms: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 security.ssl.enabled: false security.ssl.encrypt.enabled: false security.ssl.key-password: Bapuser@9000 security.ssl.keystore-password: Bapuser@9000 security.ssl.keystore: ssl/flink.keystore security.ssl.protocol: TLSv1.2 security.ssl.rest.enabled: false security.ssl.truststore-password: Bapuser@9000 security.ssl.truststore: ssl/flink.truststore security.ssl.verify-hostname: false slot.idle.timeout: 50000 slot.request.timeout: 300000 state.backend.fs.checkpointdir: hdfs://hacluster/flink/checkpoints state.backend.fs.memory-threshold: 20kb state.backend.incremental: true state.backend: rocksdb state.savepoints.dir: hdfs://hacluster/flink/savepoint task.cancellation.interval: 30000 task.cancellation.timeout: 180000 taskmanager.data.port: 32391-32455 taskmanager.data.ssl.enabled: false taskmanager.debug.memory.logIntervalMs: 0 taskmanager.debug.memory.startLogThread: false taskmanager.heap.size: 1024mb taskmanager.initial-registration-pause: 500 ms taskmanager.max-registration-pause: 30 s taskmanager.maxRegistrationDuration: 5 min taskmanager.memory.fraction: 0.7 taskmanager.memory.off-heap: false taskmanager.memory.preallocate: false taskmanager.memory.segment-size: 32768 taskmanager.network.detailed-metrics: false taskmanager.network.memory.buffers-per-channel: 2 taskmanager.network.memory.floating-buffers-per-gate: 8 taskmanager.network.memory.fraction: 0.1 taskmanager.network.memory.max: 1gb taskmanager.network.memory.min: 64mb taskmanager.network.netty.client.connectTimeoutSec: 300 taskmanager.network.netty.client.numThreads: -1 taskmanager.network.netty.num-arenas: -1 taskmanager.network.netty.sendReceiveBufferSize: 4096 taskmanager.network.netty.server.backlog: 0 taskmanager.network.netty.server.numThreads: -1 taskmanager.network.netty.transport: nio taskmanager.network.numberOfBuffers: 2048 taskmanager.network.request-backoff.initial: 100 taskmanager.network.request-backoff.max: 10000 taskmanager.numberOfTaskSlots: 1 taskmanager.refused-registration-pause: 10 s taskmanager.registration.timeout: 5 min taskmanager.rpc.port: 32326-32390 taskmanager.runtime.hashjoin-bloom-filters: false taskmanager.runtime.max-fan: 128 taskmanager.runtime.sort-spilling-threshold: 0.8 use.path.filesystem: true use.smarterleaderlatch: true web.submit.enable: false web.timeout: 10000 yarn.application-attempt-failures-validity-interval: 600000 yarn.application-attempts: 5 yarn.application-master.port: 32586-32650 yarn.heap-cutoff-min: 384 yarn.heap-cutoff-ratio: 0.25 yarn.heartbeat-delay: 5 yarn.heartbeat.container-request-interval: 500 yarn.maximum-failed-containers: 5 yarn.per-job-cluster.include-user-jar: ORDER zk.ssl.enabled: false zookeeper.clientPort.quorum: 192.168.0.82:24002,192.168.0.81:24002,192.168.0.80:24002 zookeeper.root.acl: OPEN zookeeper.sasl.disable: false zookeeper.sasl.login-context-name: Client zookeeper.sasl.service-name: zookeeper zookeeper.secureClientPort.quorum: 192.168.0.82:24002,192.168.0.81:24002,192.168.0.80:24002
-
[问题求助] FusionInsight_HD_8.2.0.1产品,在Flink SQL客户端中select 'hello'报错KeeperErrorCode = ConnectionLoss for /flink_base/flinkflinkSQL client中select 还是报错的,请帮忙指点下,哪里有问题?谢谢org.apache.flink.shaded.zookeeper3.org.apache.zookeeper.KeeperException$SessionClosedRequireAuthException: KeeperErrorCode = Session closed because client failed to authenticate for /flink_base/flink或者org.apache.flink.shaded.zookeeper3.org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /flink_base/flinkzookeeper已经启动,192.168.0.82:24002 ,而且zookeeper中的ACL权限已经设置,但是在设置配额失败[zk: 192.168.0.82:24002(CONNECTED) 2] create /flink_base/flink_base Created /flink_base/flink_base [zk: 192.168.0.82:24002(CONNECTED) 3] ls /flink_base/ Path must not end with / character [zk: 192.168.0.82:24002(CONNECTED) 4] ls /flink_base [flink, flink_base] [zk: 192.168.0.82:24002(CONNECTED) 5] [zk: 192.168.0.82:24002(CONNECTED) 5] [zk: 192.168.0.82:24002(CONNECTED) 5] [zk: 192.168.0.82:24002(CONNECTED) 5] setquota -n 1000000 /flink_base/flink Insufficient permission : /flink_base/flink [zk: 192.168.0.82:24002(CONNECTED) 6] getAcl /flink_base/flink 'world,'anyone : cdrwa [zk: 192.168.0.82:24002(CONNECTED) 7] setAcl /flink_base/flink world:anyone:rwcda [zk: 192.168.0.82:24002(CONNECTED) 8] setquota -n 1000000 /flink_base/flink Insufficient permission : /flink_base/flink [zk: 192.168.0.82:24002(CONNECTED) 9] getAcl /flink_base/ Path must not end with / character [zk: 192.168.0.82:24002(CONNECTED) 10] getAcl /flink_base 'world,'anyone : cdrwa [zk: 192.168.0.82:24002(CONNECTED) 11] getAcl /flink_base/flink 'world,'anyone : cdrwa [zk: 192.168.0.82:24002(CONNECTED) 12] ls /zookeeper/quota [beeline, elasticsearch, flink_base, graphbase, hadoop, hadoop-adapter-data, hadoop-flag, hadoop-ha, hbase, hdfs-acl-log, hive, hiveserver2, kafka, loader, mr-ha, rmstore, sparkthriftserver, sparkthriftserver2x, sparkthriftserver2x_sparkInternal_HAMode, yarn-leader-election] [zk: 192.168.0.82:24002(CONNECTED) 13] ls /zookeeper/quota/flink_base [zookeeper_limits, zookeeper_stats] [zk: 192.168.0.82:24002(CONNECTED) 5] setquota -n 1000000 /flink_base/flink Insufficient permission : /flink_base/flink tail -f /home/dmp/app/ficlient/Flink/flink/log/flink-root-sql-client-192-168-0-85.log 中的日志如下flink-conf.yaml中的全部配置如下akka.ask.timeout: 120 s akka.client-socket-worker-pool.pool-size-factor: 1.0 akka.client-socket-worker-pool.pool-size-max: 2 akka.client-socket-worker-pool.pool-size-min: 1 akka.framesize: 10485760b akka.log.lifecycle.events: false akka.lookup.timeout: 30 s akka.server-socket-worker-pool.pool-size-factor: 1.0 akka.server-socket-worker-pool.pool-size-max: 2 akka.server-socket-worker-pool.pool-size-min: 1 akka.ssl.enabled: true akka.startup-timeout: 10 s akka.tcp.timeout: 60 s akka.throughput: 15 blob.fetch.backlog: 1000 blob.fetch.num-concurrent: 50 blob.fetch.retries: 50 blob.server.port: 32456-32520 blob.service.ssl.enabled: true classloader.check-leaked-classloader: false classloader.resolve-order: child-first client.rpc.port: 32651-32720 client.timeout: 120 s compiler.delimited-informat.max-line-samples: 10 compiler.delimited-informat.max-sample-len: 2097152 compiler.delimited-informat.min-line-samples: 2 env.hadoop.conf.dir: /home/dmp/app/ficlient/Flink/flink/conf env.java.opts.client: -Djava.io.tmpdir=/home/dmp/app/ficlient/Flink/tmp env.java.opts.jobmanager: -Djava.security.krb5.conf=/opt/huawei/Bigdata/common/runtime/krb5.conf -Djava.io.tmpdir=${PWD}/tmp -Des.security.indication=true env.java.opts.taskmanager: -Djava.security.krb5.conf=/opt/huawei/Bigdata/common/runtime/krb5.conf -Djava.io.tmpdir=${PWD}/tmp -Des.security.indication=true env.java.opts: -Xloggc:<LOG_DIR>/gc.log -XX:+PrintGCDetails -XX:-OmitStackTraceInFastThrow -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=20 -XX:GCLogFileSize=20M -Djdk.tls.ephemeralDHKeySize=3072 -Djava.library.path=${HADOOP_COMMON_HOME}/lib/native -Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false -Dbeetle.application.home.path=/opt/huawei/Bigdata/common/runtime/security/config -Dwcc.configuration.path=/opt/huawei/Bigdata/common/runtime/security/config -Dscc.configuration.path=/opt/huawei/Bigdata/common/runtime/securityforscc/config -Dscc.bigdata.common=/opt/huawei/Bigdata/common/runtime env.yarn.conf.dir: /home/dmp/app/ficlient/Flink/flink/conf flink.security.enable: true flinkserver.alarm.cert.skip: true flinkserver.host.ip: fs.output.always-create-directory: false fs.overwrite-files: false heartbeat.interval: 10000 heartbeat.timeout: 120000 high-availability.job.delay: 10 s high-availability.storageDir: hdfs://hacluster/flink/recovery high-availability.zookeeper.client.acl: creator high-availability.zookeeper.client.connection-timeout: 90000 high-availability.zookeeper.client.max-retry-attempts: 5 high-availability.zookeeper.client.retry-wait: 5000 high-availability.zookeeper.client.session-timeout: 90000 high-availability.zookeeper.client.tolerate-suspended-connections: true high-availability.zookeeper.path.root: /flink high-availability.zookeeper.path.under.quota: /flink_base high-availability.zookeeper.quorum: 192.168.0.82:24002,192.168.0.81:24002,192.168.0.80:24002 high-availability.zookeeper.quota.enabled: true high-availability: zookeeper job.alarm.enable: true jobmanager.heap.size: 1024mb jobmanager.web.403-redirect-url: https://192.168.0.82:28443/web/pages/error/403.html jobmanager.web.404-redirect-url: https://192.168.0.82:28443/web/pages/error/404.html jobmanager.web.415-redirect-url: https://192.168.0.82:28443/web/pages/error/415.html jobmanager.web.500-redirect-url: https://192.168.0.82:28443/web/pages/error/500.html jobmanager.web.access-control-allow-origin: * jobmanager.web.accesslog.enable: true jobmanager.web.allow-access-address: * jobmanager.web.backpressure.cleanup-interval: 600000 jobmanager.web.backpressure.delay-between-samples: 50 jobmanager.web.backpressure.num-samples: 100 jobmanager.web.backpressure.refresh-interval: 60000 jobmanager.web.cache-directive: no-store jobmanager.web.checkpoints.disable: false jobmanager.web.checkpoints.history: 10 jobmanager.web.expires-time: 0 jobmanager.web.history: 5 jobmanager.web.logout-timer: 600000 jobmanager.web.pragma-value: no-cache jobmanager.web.refresh-interval: 3000 jobmanager.web.ssl.enabled: false jobmanager.web.x-frame-options: DENY library-cache-manager.cleanup.interval: 3600 metrics.internal.query-service.port: 28844-28943 metrics.reporter.alarm.factory.class: com.huawei.mrs.flink.alarm.FlinkAlarmReporterFactory metrics.reporter.alarm.interval: 30 s metrics.reporter.alarm.job.alarm.checkpoint.consecutive.failures.num: 5 metrics.reporter.alarm.job.alarm.failure.restart.rate: 80 metrics.reporter.alarm.job.alarm.task.backpressure.duration: 180 s metrics.reporter: alarm nettyconnector.message.delimiter: $_ nettyconnector.registerserver.topic.storage: /flink/nettyconnector nettyconnector.sinkserver.port.range: 28444-28843 nettyconnector.ssl.enabled: false parallelism.default: 1 query.client.network-threads: 0 query.proxy.network-threads: 0 query.proxy.ports: 32541-32560 query.proxy.query-threads: 0 query.server.network-threads: 0 query.server.ports: 32521-32540 query.server.query-threads: 0 resourcemanager.taskmanager-timeout: 300000 rest.await-leader-timeout: 30000 rest.bind-port: 32261-32325 rest.client.max-content-length: 104857600 rest.connection-timeout: 15000 rest.idleness-timeout: 300000 rest.retry.delay: 3000 rest.retry.max-attempts: 20 rest.server.max-content-length: 104857600 rest.server.numThreads: 4 restart-strategy.failure-rate.delay: 10 s restart-strategy.failure-rate.failure-rate-interval: 60 s restart-strategy.failure-rate.max-failures-per-interval: 1 restart-strategy.fixed-delay.attempts: 3 restart-strategy.fixed-delay.delay: 10 s restart-strategy: none security.cookie: 9477298cd52a3e409ed0bc570bdc795179fcc7c301a1225e22f47fe0a3db47c2 security.enable: true security.kerberos.login.contexts: Client,KafkaClient security.kerberos.login.keytab: security.kerberos.login.principal: security.kerberos.login.use-ticket-cache: true security.networkwide.listen.restrict: true security.ssl.algorithms: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 security.ssl.enabled: false security.ssl.encrypt.enabled: false security.ssl.key-password: Bapuser@9000 security.ssl.keystore-password: Bapuser@9000 security.ssl.keystore: ssl/flink.keystore security.ssl.protocol: TLSv1.2 security.ssl.rest.enabled: false security.ssl.truststore-password: Bapuser@9000 security.ssl.truststore: ssl/flink.truststore security.ssl.verify-hostname: false slot.idle.timeout: 50000 slot.request.timeout: 300000 state.backend.fs.checkpointdir: hdfs://hacluster/flink/checkpoints state.backend.fs.memory-threshold: 20kb state.backend.incremental: true state.backend: rocksdb state.savepoints.dir: hdfs://hacluster/flink/savepoint task.cancellation.interval: 30000 task.cancellation.timeout: 180000 taskmanager.data.port: 32391-32455 taskmanager.data.ssl.enabled: false taskmanager.debug.memory.logIntervalMs: 0 taskmanager.debug.memory.startLogThread: false taskmanager.heap.size: 1024mb taskmanager.initial-registration-pause: 500 ms taskmanager.max-registration-pause: 30 s taskmanager.maxRegistrationDuration: 5 min taskmanager.memory.fraction: 0.7 taskmanager.memory.off-heap: false taskmanager.memory.preallocate: false taskmanager.memory.segment-size: 32768 taskmanager.network.detailed-metrics: false taskmanager.network.memory.buffers-per-channel: 2 taskmanager.network.memory.floating-buffers-per-gate: 8 taskmanager.network.memory.fraction: 0.1 taskmanager.network.memory.max: 1gb taskmanager.network.memory.min: 64mb taskmanager.network.netty.client.connectTimeoutSec: 300 taskmanager.network.netty.client.numThreads: -1 taskmanager.network.netty.num-arenas: -1 taskmanager.network.netty.sendReceiveBufferSize: 4096 taskmanager.network.netty.server.backlog: 0 taskmanager.network.netty.server.numThreads: -1 taskmanager.network.netty.transport: nio taskmanager.network.numberOfBuffers: 2048 taskmanager.network.request-backoff.initial: 100 taskmanager.network.request-backoff.max: 10000 taskmanager.numberOfTaskSlots: 1 taskmanager.refused-registration-pause: 10 s taskmanager.registration.timeout: 5 min taskmanager.rpc.port: 32326-32390 taskmanager.runtime.hashjoin-bloom-filters: false taskmanager.runtime.max-fan: 128 taskmanager.runtime.sort-spilling-threshold: 0.8 use.path.filesystem: true use.smarterleaderlatch: true web.submit.enable: false web.timeout: 10000 yarn.application-attempt-failures-validity-interval: 600000 yarn.application-attempts: 5 yarn.application-master.port: 32586-32650 yarn.heap-cutoff-min: 384 yarn.heap-cutoff-ratio: 0.25 yarn.heartbeat-delay: 5 yarn.heartbeat.container-request-interval: 500 yarn.maximum-failed-containers: 5 yarn.per-job-cluster.include-user-jar: ORDER zk.ssl.enabled: false zookeeper.clientPort.quorum: 192.168.0.82:24002,192.168.0.81:24002,192.168.0.80:24002 zookeeper.root.acl: OPEN zookeeper.sasl.disable: false zookeeper.sasl.login-context-name: Client zookeeper.sasl.service-name: zookeeper zookeeper.secureClientPort.quorum: 192.168.0.82:24002,192.168.0.81:24002,192.168.0.80:24002
-
[问题求助] FusionInsight_HD_8.2.0.1产品,在Flink SQL客户端中select 'hello'报错KeeperErrorCode = ConnectionLoss for /flink_base/flink1.在flink sql client中执行sql 直接报错[ERROR] Could not execute SQL statement. Reason: org.apache.flink.shaded.zookeeper3.org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /flink_base/flink 2.而且进入zookeeper中查询也是报错,求解求解[omm@192-168-0-82 zookeeper]$ pwd /opt/huawei/Bigdata/FusionInsight_HD_8.2.0.1/install/FusionInsight-Zookeeper-3.6.3/zookeeper [omm@192-168-0-82 zookeeper]$ bin/zkCli.sh -server 192.168.0.82:24002 Connecting to 192.168.0.82:24002 Welcome to ZooKeeper! JLine support is enabled WATCHER:: WatchedEvent state:SyncConnected type:None path:null [zk: 192.168.0.82:24002(CONNECTING) 0] ls / KeeperErrorCode = Session closed because client failed to authenticate for / [zk: 192.168.0.82:24002(CONNECTED) 1] WATCHER:: WatchedEvent state:Disconnected type:None path:null WATCHER:: WatchedEvent state:SyncConnected type:None path:null WATCHER:: WatchedEvent state:Disconnected type:None path:null 后面是一直循环WATCHER:,flink-conf.yaml中的部分设置如下 flink.security.enable: true flinkserver.alarm.cert.skip: true flinkserver.host.ip: fs.output.always-create-directory: false fs.overwrite-files: false heartbeat.interval: 10000 heartbeat.timeout: 120000 high-availability.job.delay: 10 s high-availability.storageDir: hdfs://hacluster/flink/recovery high-availability.zookeeper.client.acl: creator high-availability.zookeeper.client.connection-timeout: 90000 high-availability.zookeeper.client.max-retry-attempts: 5 high-availability.zookeeper.client.retry-wait: 5000 high-availability.zookeeper.client.session-timeout: 90000 high-availability.zookeeper.client.tolerate-suspended-connections: true high-availability.zookeeper.path.root: /flink high-availability.zookeeper.path.under.quota: /flink_base high-availability.zookeeper.quorum: 192.168.0.82:24002,192.168.0.81:24002,192.168.0.80:24002 high-availability.zookeeper.quota.enabled: true high-availability: zookeeper yarn.application-attempts: 5 yarn.application-master.port: 32586-32650 yarn.heap-cutoff-min: 384 yarn.heap-cutoff-ratio: 0.25 yarn.heartbeat-delay: 5 yarn.heartbeat.container-request-interval: 500 yarn.maximum-failed-containers: 5 yarn.per-job-cluster.include-user-jar: ORDER zk.ssl.enabled: false zookeeper.clientPort.quorum: 192.168.0.82:24002,192.168.0.81:24002,192.168.0.80:24002 zookeeper.root.acl: OPEN zookeeper.sasl.disable: false zookeeper.sasl.login-context-name: Client zookeeper.sasl.service-name: zookeeper zookeeper.secureClientPort.quorum: 192.168.0.82:24002,192.168.0.81:24002,192.168.0.80:24002
-
前言基于java使用SDK实现图像识别,主要以媒资图像标签和名人识别为例。一、环境配置Maven(没有直接下载华为的SDK包,而是使用Maven安装依赖)JDK19(官方的SDK包要求JDK版本必须高于JDK8版本,大家根据自己只要满足版本要求即可)开发工具:IDEA 2023.3(其他版本也可)能创建Maven项目即可开通图像识别服务(目前是免费体验):这里我开通的是图像标签/媒资图像标签和名人识别服务。设置访问密钥服务区域:我开通的服务区域是华北-北京四关键步骤Maven项目的创建和Java环境变量的配置我就不再赘诉,这是大家学习java早已熟练掌握的,这里只讲诉易错的。开通图像识别服务 华为云首页就有云产品体验区(找不到就在搜索栏检索),勾选AI: 点击“立即体验”后,找到服务列表,开通你想要的服务(点击开通): 设置访问密钥 在控制台找到“我的凭证”: 找到“访问密钥”,如果没有就新增,新增后一定要下载密钥的CSV文件,他会有提示让你下载,防止你忘记: 下载完csv文件后用记事本打开即可看到AK和SK: Maven引入依赖配置 版本可以自己切换 <dependency> <groupId>com.huaweicloud.sdk</groupId> <artifactId>huaweicloud-sdk-image</artifactId> <version>3.1.8</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.70</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.4.16</version> </dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.16.0</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.13.0</version> </dependency>二、图像识别实例媒资图像标签功能介绍:对用户传入的图像可以返回图像中的物体名称、所属类别及置信度信息。使用图片是网上的,仅作学习使用: 代码如下:/** * @Version: 1.0.0 * @Author: Dragon_王 * @ClassName: RunImageMediaTaggingSolution * @Description: 媒资图像标签 * @Date: 2024/1/8 11:51 */ /** * 此demo仅供测试使用,强烈建议使用SDK * 使用前需配置依赖jar包。jar包可通过下载SDK获取 */ import com.huaweicloud.sdk.core.auth.ICredential; import com.huaweicloud.sdk.core.auth.BasicCredentials; import com.huaweicloud.sdk.core.exception.ConnectionException; import com.huaweicloud.sdk.core.exception.RequestTimeoutException; import com.huaweicloud.sdk.core.exception.ServiceResponseException; import com.huaweicloud.sdk.image.v2.region.ImageRegion; import com.huaweicloud.sdk.image.v2.*; import com.huaweicloud.sdk.image.v2.model.*; public class RunImageMediaTaggingSolution { public static void main(String[] args) { //此处需要输入您的AK/SK信息 String ak = "你的AK"; String sk = "你的SK"; ICredential auth = new BasicCredentials() .withAk(ak) .withSk(sk); ImageClient client = ImageClient.newBuilder() .withCredential(auth) .withRegion(ImageRegion.valueOf("cn-north-4")) //此处替换为您开通服务的区域 .build(); RunImageMediaTaggingRequest request = new RunImageMediaTaggingRequest(); ImageMediaTaggingReq body = new ImageMediaTaggingReq(); body.withThreshold(10f); body.withLanguage("zh"); body.withUrl("https://tse2-mm.cn.bing.net/th/id/OIP-C.SIuEnb1-arhtDNqfdICVqAHaE7?rs=1&pid=ImgDetMain"); //此处替换为公网可以访问的图片地址 request.withBody(body); try { RunImageMediaTaggingResponse response = client.runImageMediaTagging(request); System.out.println(response.toString()); } catch (ConnectionException e) { e.printStackTrace(); } catch (RequestTimeoutException e) { e.printStackTrace(); } catch (ServiceResponseException e) { e.printStackTrace(); System.out.println(e.getHttpStatusCode()); System.out.println(e.getErrorCode()); System.out.println(e.getErrorMsg()); } } }运行结果: //运行结果如下 class RunImageMediaTaggingResponse { result: class ImageMediaTaggingResponseResult { tags: [class ImageMediaTaggingItemBody { confidence: 83.63 type: 动物 tag: 金毛犬 i18nTag: class ImageMediaTaggingItemBodyI18nTag { zh: 金毛犬 en: Golden retriever } i18nType: class ImageMediaTaggingItemBodyI18nType { zh: 动物 en: Animal } instances: [] }, class ImageMediaTaggingItemBody { confidence: 81.78 type: 动物 tag: 金毛 i18nTag: class ImageMediaTaggingItemBodyI18nTag { zh: 金毛 en: Golden hair } i18nType: class ImageMediaTaggingItemBodyI18nType { zh: 动物 en: Animal } instances: [] }, class ImageMediaTaggingItemBody { confidence: 77.00 type: 动物 tag: 金毛寻猎犬 i18nTag: class ImageMediaTaggingItemBodyI18nTag { zh: 金毛寻猎犬 en: Golden Retriever } i18nType: class ImageMediaTaggingItemBodyI18nType { zh: 动物 en: Animal } instances: [] }, class ImageMediaTaggingItemBody { confidence: 62.60 type: 动物 tag: 贵妇犬 i18nTag: class ImageMediaTaggingItemBodyI18nTag { zh: 贵妇犬 en: Poodle } i18nType: class ImageMediaTaggingItemBodyI18nType { zh: 动物 en: Animal } instances: [] }, class ImageMediaTaggingItemBody { confidence: 59.02 type: 生活 tag: 狗链 i18nTag: class ImageMediaTaggingItemBodyI18nTag { zh: 狗链 en: Dog chain } i18nType: class ImageMediaTaggingItemBodyI18nType { zh: 生活 en: Life } instances: [] }, class ImageMediaTaggingItemBody { confidence: 53.84 type: 动物 tag: 宠物狗 i18nTag: class ImageMediaTaggingItemBodyI18nTag { zh: 宠物狗 en: Pet dog } i18nType: class ImageMediaTaggingItemBodyI18nType { zh: 动物 en: Animal } instances: [] }, class ImageMediaTaggingItemBody { confidence: 48.01 type: 动物 tag: 狗狗 i18nTag: class ImageMediaTaggingItemBodyI18nTag { zh: 狗狗 en: Dog } i18nType: class ImageMediaTaggingItemBodyI18nType { zh: 动物 en: Animal } instances: [] }, class ImageMediaTaggingItemBody { confidence: 44.02 type: 动物 tag: 犬 i18nTag: class ImageMediaTaggingItemBodyI18nTag { zh: 犬 en: Dog } i18nType: class ImageMediaTaggingItemBodyI18nType { zh: 动物 en: Animal } instances: [] }, class ImageMediaTaggingItemBody { confidence: 42.11 type: 动物 tag: 纯种犬 i18nTag: class ImageMediaTaggingItemBodyI18nTag { zh: 纯种犬 en: Purebred dog } i18nType: class ImageMediaTaggingItemBodyI18nType { zh: 动物 en: Animal } instances: [] }, class ImageMediaTaggingItemBody { confidence: 38.65 type: 动物 tag: 中华田园犬 i18nTag: class ImageMediaTaggingItemBodyI18nTag { zh: 中华田园犬 en: Chinese pastoral dog } i18nType: class ImageMediaTaggingItemBodyI18nType { zh: 动物 en: Animal } instances: [] }] } } Process finished with exit code 0名人识别功能介绍:分析并识别图片中包含的敏感人物、明星及网红人物,返回人物信息及人脸坐标。使用照片是网上的照片,仅作学习使用: 代码如下:/** * @Version: 1.0.0 * @Author: Dragon_王 * @ClassName: RunCelebrityRecognitionSolution * @Description: 媒资标签 * @Date: 2024/1/9 16:23 */ import com.alibaba.fastjson.JSON; import com.huaweicloud.sdk.core.auth.ICredential; import com.huaweicloud.sdk.core.auth.BasicCredentials; import com.huaweicloud.sdk.core.exception.ConnectionException; import com.huaweicloud.sdk.core.exception.RequestTimeoutException; import com.huaweicloud.sdk.core.exception.ServiceResponseException; import com.huaweicloud.sdk.image.v2.ImageClient; import com.huaweicloud.sdk.image.v2.model.RunCelebrityRecognitionRequest; import com.huaweicloud.sdk.image.v2.region.ImageRegion; import com.huaweicloud.sdk.image.v2.model.CelebrityRecognitionReq; import com.huaweicloud.sdk.image.v2.model.RunCelebrityRecognitionResponse; public class RunCelebrityRecognitionSolution { public static void main(String[] args) { // 认证用的ak和sk硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全 // 本示例以ak和sk保存在环境变量中来实现身份验证为例,运行本示例前请先在本地环境中设置环境变量HUAWEICLOUD_SDK_AK和HUAWEICLOUD_SDK_SK String ak = "你的AK"; String sk = "你的SK"; ICredential auth = new BasicCredentials() .withAk(ak) .withSk(sk); ImageClient client = ImageClient.newBuilder() .withCredential(auth) .withRegion(ImageRegion.valueOf("cn-north-4")) //此处替换为您开通服务的区域 .build(); RunCelebrityRecognitionRequest request = new RunCelebrityRecognitionRequest(); CelebrityRecognitionReq body = new CelebrityRecognitionReq(); body.withThreshold(0f); body.withUrl("https://tse1-mm.cn.bing.net/th/id/OIP-C.tM6jifW1xaCDP7Kia9QiYwHaKD?rs=1&pid=ImgDetMain"); //此处替换为公网可以访问的图片地址 request.withBody(body); try { RunCelebrityRecognitionResponse response = client.runCelebrityRecognition(request); System.out.println(response.getHttpStatusCode()); System.out.println(JSON.toJSONString(response)); } catch (ConnectionException e) { e.printStackTrace(); } catch (RequestTimeoutException e) { e.printStackTrace(); } catch (ServiceResponseException e) { e.printStackTrace(); System.out.println(e.getHttpStatusCode()); System.out.println(e.getErrorCode()); System.out.println(e.getErrorMsg()); } } }运行结果:200 {"httpStatusCode":200,"result":[{"confidence":0.9985551,"faceDetail":{"w":132,"h":186,"x":197,"y":79},"label":"成龙"}]} Process finished with exit code 0总结以上就是华为云的AI图像识别服务调用,这里提供官方文档
-
Java课程设计 前言 来csdn也有两年了,在这期间学了很多的知识,也跟着许多的大神做了几个小项目。但自己也在想什么时候能够有个自己的项目,之前在学校做过一个基于集合存储数据的学生信息管理系统,现在想着改进一下,于是趁着暑假做了一个小项目吧(基于mysql+jdbc+java swing的学生成绩信息管理系统)。一来是巩固自己的学习成果,二来是记录自己的学习历程,期待后面能做出更多的项目吧。 设计需求和思路 设计需求 1.利用jdbc将java程序与mysql建立连接 2.利用java swing将学生信息和成绩信息显现出来 3.通过使用sql指令来实现对学生信息和成绩信息的crud(增查改删)操作 设计思路 1.利用Navicat创建两个数据表(stu和classes),同时两个数据表用外键约束连接( CONSTRAINT `fk_classes_stu` FOREIGN KEY (`class_id`) REFERENCES `stu` (`stu_num`) ON DELETE CASCADE ) 2.使用sql指令对数据表中数据进行增删改查,并通过java swing显示 3.查询所有学生信息,利用连接查询将两个数据表的信息一并显示 详细操作 1.设计主界面(登录注册界面) 账号和密码通过HashMap来存储,账号为键密码为值,利用其基本方法来添加账号密码(注册),以及登录。 package view; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.HashMap; import java.util.Map; public class MainView extends JFrame { private Map<String,String> userhashmap=new HashMap<>(); JPanel p1=new JPanel(); JPanel p2=new JPanel(); JPanel p3=new JPanel(); JPanel p4=new JPanel(); JLabel welcome=new JLabel("欢迎来到学生信息管理系统"); JLabel username=new JLabel("账号:"); JLabel password=new JLabel("密码:"); JTextField usernametext=new JTextField(10); JPasswordField passwordField=new JPasswordField(10); JButton confirm=new JButton("确认"); JButton exit=new JButton("退出"); JButton register=new JButton("注册"); public MainView() { this.setTitle("学生信息管理系统"); this.setSize(800, 500); this.setLayout(new GridLayout(4, 1,10,10)); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); p4.add(welcome); p1.add(username); p1.add(usernametext); p2.add(password); p2.add(passwordField); p3.add(confirm); p3.add(register); p3.add(exit); this.add(p4); this.add(p1); this.add(p2); this.add(p3); register.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if(e.getSource()==register){ if(userhashmap.containsKey(usernametext.getText())){ JOptionPane.showMessageDialog(null,"注册失败,您的账号已存在","警告",JOptionPane.WARNING_MESSAGE); return; } userhashmap.put(usernametext.getText(),passwordField.getText()); JOptionPane.showMessageDialog(null,"注册成功","通知",JOptionPane.INFORMATION_MESSAGE); } } }); confirm.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == confirm) { if (userhashmap.containsKey(usernametext.getText())) { if (userhashmap.get(usernametext.getText()).equals(passwordField.getText())) { JOptionPane.showMessageDialog(null,"登陆成功","通知",JOptionPane.INFORMATION_MESSAGE); dispose(); ManagerView mv=new ManagerView(); mv.setVisible(true); } else { JOptionPane.showMessageDialog(null,"密码错误","警告",JOptionPane.WARNING_MESSAGE); } } else{ JOptionPane.showMessageDialog(null,"该用户不存在","警告",JOptionPane.WARNING_MESSAGE); } } } }); exit.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.exit(0); } }); } public static void main(String[] args) { MainView m=new MainView(); m.setVisible(true); } } 2.设计学生信息管理界面和成绩信息管理界面 使用GridBagLayout布局设置左边为学生信息管理的按钮,右边为成绩信息管理的按钮 package view; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class ManagerView extends JFrame{ JButton insert=new JButton("添加学生信息"); JButton delete=new JButton("删除学生"); JButton update=new JButton("学生信息修改"); JButton query=new JButton("查询学生信息"); JButton queryall=new JButton("查询所有学生信息"); JButton insertclass=new JButton("添加成绩信息"); JButton deleteclass=new JButton("删除成绩信息"); JButton updateclass=new JButton("修改成绩信息"); JLabel labelstu=new JLabel("学生管理系统");//设置“学生管理系统”标签 JLabel labelclass=new JLabel("成绩管理系统");//设置“成绩管理系统”标签 public ManagerView(){ this.setTitle("学生成绩管理"); this.setSize(1200,500); this.setLayout(new GridBagLayout()); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //设置每个按钮长,高为140,120 Dimension dimension=new Dimension(140,30);//通过setPreferredSize()方法来设置按钮和标签大小,但要传入Dimension对象 insert.setPreferredSize(dimension); delete.setPreferredSize(dimension); update.setPreferredSize(dimension); query.setPreferredSize(dimension); queryall.setPreferredSize(dimension); insertclass.setPreferredSize(dimension); deleteclass.setPreferredSize(dimension); updateclass.setPreferredSize(dimension); labelstu.setPreferredSize(dimension); labelclass.setPreferredSize(dimension); GridBagConstraints constraintsleft=new GridBagConstraints(); constraintsleft.gridx = 0; // 列为0 constraintsleft.gridy = GridBagConstraints.RELATIVE; // 按钮的行相对于前一个按钮的行 constraintsleft.anchor = GridBagConstraints.CENTER; // 设置水平方向上的位置居中 constraintsleft.fill = GridBagConstraints.HORIZONTAL; // 填充水平方向 /*constraintsleft.weightx = 0.5; // 水平方向上的权重为0.5*/ constraintsleft.insets = new Insets(5, 5, 5, 200); // 设置按钮的内边距 constraintsleft.ipadx = 10; this.add(labelstu,constraintsleft); this.add(insert,constraintsleft); this.add(delete,constraintsleft); this.add(update,constraintsleft); this.add(query,constraintsleft); this.add(queryall,constraintsleft); GridBagConstraints constraintsright=new GridBagConstraints(); constraintsright.gridx=1; constraintsleft.gridy = GridBagConstraints.RELATIVE; // 按钮的行相对于前一个按钮的行 constraintsleft.anchor = GridBagConstraints.CENTER; // 设置水平方向上的位置居中 constraintsleft.fill = GridBagConstraints.HORIZONTAL; // 填充水平方向 /*constraintsleft.weightx = 0.5; // 水平方向上的权重为0.5*/ constraintsleft.insets = new Insets(5, 200, 5, 5); // 设置按钮的内边距 constraintsleft.ipadx = 10; this.add(labelclass,constraintsright); this.add(insertclass,constraintsright); this.add(deleteclass,constraintsright); this.add(updateclass,constraintsright); insert.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { InsertStuView insertStuView=new InsertStuView(); insertStuView.setVisible(true); } }); delete.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { DeleteStuView deleteStuView=new DeleteStuView(); deleteStuView.setVisible(true); } }); update.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { UpdateStuview updateStuview=new UpdateStuview(); updateStuview.setVisible(true); } }); query.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { QueryStuView queryStuView=new QueryStuView(); queryStuView.setVisible(true); } }); insertclass.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { InsertClassView insertClassView=new InsertClassView(); insertClassView.setVisible(true); } }); deleteclass.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { DeleteClassView deleteClassView=new DeleteClassView(); deleteClassView.setVisible(true); } }); updateclass.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { UpdateClassView updateClassView =new UpdateClassView(); updateClassView.setVisible(true); } }); /* p1.add(insert); p2.add(delete); p3.add(query); p4.add(update); p5.add(orderby);*/ queryall.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e) { QueryAllView queryAllView=new QueryAllView(); queryAllView.setVisible(true); } }); } } 3.设计学生信息操作 添加学生信息 package view; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import service.StuManage; public class InsertStuView extends JFrame { JLabel labelname=new JLabel("请输入您的姓名"); JLabel labelgender=new JLabel("请输入您的性别"); JLabel labelid=new JLabel("请输入您的学号"); JTextField textname=new JTextField(15); JTextField textgender=new JTextField(15); JTextField textid=new JTextField(15); JButton confirm=new JButton("确定"); JButton cancel=new JButton("取消"); JPanel p1=new JPanel(); JPanel p2=new JPanel(); JPanel p3=new JPanel(); JPanel p4=new JPanel(); public InsertStuView(){ this.setSize(500,300); this.setTitle("请添加学生信息"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLayout(new GridLayout(4,1,10,10)); p1.add(labelname); p1.add(textname); p2.add(labelgender); p2.add(textgender); p3.add(labelid); p3.add(textid); p4.add(confirm); p4.add(cancel); this.add(p1); this.add(p2); this.add(p3); this.add(p4); confirm.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { StuManage.insertStudata(textname.getText(),textgender.getText(),textid.getText()); } catch (Exception ex) { JOptionPane.showMessageDialog(null,"添加失败","警告",JOptionPane.WARNING_MESSAGE); } dispose(); } }); cancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { dispose(); } }); } } 通过学号删除学生,因为学号不会重复 package view; import service.StuManage; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class DeleteStuView extends JFrame { JLabel labelid=new JLabel("请输入您想删除学生的学号"); JTextField textField=new JTextField(15); JPanel p1=new JPanel(); JPanel p2=new JPanel(); JButton confirm=new JButton("确定"); JButton cancel=new JButton("取消"); public DeleteStuView(){ this.setSize(500,300); this.setLayout(new GridLayout(2,1,0,0)); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setTitle("删除学生"); p1.add(labelid); p1.add(textField); p2.add(confirm); p2.add(cancel); p1.setBorder(BorderFactory.createEmptyBorder(70,0,0,0)); this.add(p1); this.add(p2); confirm.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try{ StuManage.deleteStudata(textField.getText()); }catch(Exception ex){ JOptionPane.showMessageDialog(null,"删除失败","警告",JOptionPane.WARNING_MESSAGE); } dispose(); } }); cancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { dispose(); } }); } } 学生信息修改 package view; import service.StuManage; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class UpdateStuview extends JFrame{ JLabel labeloldid=new JLabel("请输入您要修改学生的学号"); JLabel labelname=new JLabel("请输入您要修改后的姓名"); JLabel labelgender=new JLabel("请输入您要修改后的性别"); JLabel labelid=new JLabel("请输入您要修改后的学号"); JTextField textFieldoldid=new JTextField(15); JTextField textname=new JTextField(15); JTextField textgender=new JTextField(15); JTextField textid=new JTextField(15); JButton confirm=new JButton("确定"); JButton cancel=new JButton("取消"); JPanel p1=new JPanel(); JPanel p2=new JPanel(); JPanel p3=new JPanel(); JPanel p4=new JPanel(); JPanel p5=new JPanel(); public UpdateStuview(){ this.setSize(500,300); this.setTitle("请修改学生信息"); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLayout(new GridLayout(5,1,10,10)); p1.add(labeloldid); p1.add(textFieldoldid); p2.add(labelname); p2.add(textname); p3.add(labelgender); p3.add(textgender); p4.add(labelid); p4.add(textid); p5.add(confirm); p5.add(cancel); this.add(p1); this.add(p2); this.add(p3); this.add(p4); this.add(p5); confirm.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { StuManage.updateStudata(textname.getText(),textgender.getText(),textid.getText(),textFieldoldid.getText()); } catch (Exception ex) { JOptionPane.showMessageDialog(null,"修改失败","警告",JOptionPane.WARNING_MESSAGE); } dispose(); } }); cancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { dispose(); } }); } } 查询学生信息 package view; import service.ClassManage; import javax.swing.*; import javax.swing.table.DefaultTableModel; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class QueryStuView extends JFrame { JLabel id=new JLabel("请输入学生的id"); JTextField textid=new JTextField(15); JButton confirm=new JButton("确定"); JButton cancel=new JButton("取消"); JLabel labelstu=new JLabel("学生信息表"); JLabel labelscore=new JLabel("成绩信息表"); JPanel p1=new JPanel(); JPanel p2=new JPanel(); JPanel p3=new JPanel(); JPanel p4=new JPanel(); String[] stucolumnname={"姓名","性别","学号"}; String[] scorecolumnname={"学科","分数","教师"}; public QueryStuView(){ this.setLayout(new GridLayout(4,4,10,10)); this.setTitle("学生信息查询"); this.setSize(1000,700); DefaultTableModel stumodel=new DefaultTableModel(); DefaultTableModel scoremodel=new DefaultTableModel(); stumodel.setColumnIdentifiers(stucolumnname); scoremodel.setColumnIdentifiers(scorecolumnname); JTable stutable = new JTable(stumodel); JTable scoretable=new JTable(scoremodel); JScrollPane scrollstu=new JScrollPane(stutable); JScrollPane scrollscore=new JScrollPane(scoretable); p1.setBorder(BorderFactory.createEmptyBorder(70,0,0,0)); p1.add(id); p1.add(textid); p2.add(confirm); p2.add(cancel); p3.add(labelstu); p3.add(scrollstu); p4.add(labelscore); p4.add(scrollscore); this.add(p1); this.add(p2); this.add(p3); this.add(p4); confirm.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try{ stumodel.setRowCount(0); scoremodel.setRowCount(0); ClassManage.querystu(textid.getText(),stumodel,scoremodel); }catch(Exception ex){ JOptionPane.showMessageDialog(null,"查找失败","警告",JOptionPane.WARNING_MESSAGE); } } }); cancel.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { dispose(); } }); } } 查询所有学生信息 package view; import service.ClassManage; import javax.swing.*; import javax.swing.table.DefaultTableModel; public class QueryAllView extends JFrame{ JLabel text=new JLabel("学生信息查询"); DefaultTableModel model=new DefaultTableModel(); JTable queryall=new JTable(model); JScrollPane jScrollPane=new JScrollPane(queryall); JPanel p1=new JPanel(); JPanel p2=new JPanel(); public QueryAllView(){ this.setTitle("学生成绩查询"); this.setSize(1000,700); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); String[] columnname={"姓名","性别","学号","科目","分数"}; model.setColumnIdentifiers(columnname); p1.add(text); p2.add(jScrollPane); this.add(p1); this.add(p2); try{ ClassManage.queryall(model); }catch(Exception ex){ JOptionPane.showMessageDialog(null,"查询失败","警告",JOptionPane.WARNING_MESSAGE); } } } ———————————————— 版权声明:本文为CSDN博主「Java雪荷」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/xyendjsj/article/details/131774615
上滑加载中
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签