ssh和ssm面试题

ssh

ssh特点

struts2+spring+hibernate

struts2负责web层,hibernate负责持久层,spring统一对对象进行管理完成ioc,di,aop

SSH优缺点

缺点:

配置文件多,ssh的配置繁琐。

项目启动慢,ssh组合的项目在windows平台下的服务器中启动一下,最少要15秒,有时多达30秒

 

优点:

层次结构清晰,便于维护。

层次之间耦合性小,便于团队开发。

spring

spring介绍

为了解决企业应用程序开发的复杂性的问题而创建的,提高开发效率,轻量级的开源框架。

Spring的核心是控制反转(IoC)和面向切面(AOP)

Spring致力于J2EE应用的各层的解决方案,而不是仅仅专注于某一层的方案。

Spring并不想取代那些已有的框架,而是与它们无缝地整合。

 

优点:

  • spring容器管理bean可以松耦合的编写业务代码
  • spring的aop可以方便的进行事务,日志等管理
  • 高效的开发应用程序
  • 主流的框架都提供支持

 

 

spring常用模块

分别是Spring Core,AOP,ORM,DAO,MVC,WEB,Context。

spring常用模块简介

核心容器(Spring Core)

Spring的所有功能都依赖于该类库,Core主要实现IOC功能,Spring几乎所有功能都是借助IOC实现的。

  

应用上下文(Spring Context)

Context模块提供框架式的Bean访问方式,其他程序可以通过Context访问Spring的Bean资源,相当于资源注入。

 

面向切面编程(Spring AOP)

  AOP(Aspect Oriented Programming)

  通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。

 

DAO模块(Spring DAO)

提供对JDBC的支持,对JDBC进行封装,允许JDBC使用Spring资源,并能统一管理JDBC事物

 

对象实体映射(Spring ORM)

  ORM(Object Relational Mapping)

Spring 的ORM模块提供对常用的ORM框架的管理和辅助支持,Spring支持常用的Hibernate,mybtis等框架的支持,Spring本身并不对ORM进行实现,仅对常见的ORM框架进行封装,并对其进行管理

  

Web模块(Spring Web)

  Web上下文模块建立在应用程序上下文模块之上,为基于web的应用程序提供了上下文。所以Spring框架支持与Struts集成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

 

MVC模块(Spring Web MVC)

  MVC(Model View Controller)

MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来由JavaBean来构成,存放于m当中,而视图是一个接口,负责实现模型,控制器表示逻辑代码。

spring优点

  • 可以将对象之间的依赖关系交给Spring,降低组件之间的耦合性,让我们更专注于应用逻辑
  • 利用Spring的AOP,可以很方便面向切面编程。
  • 对主流的框架提供了很好的集成支持,如Hibernate,Struts2,JPA等
  • .可以提供众多服务,事务管理,WS等。

spring工作原理

spring利用IOC(控制反转)进行对象的创建、初始化、销毁等,由spring容器控制对象的生命周期。

spring通过DI(依赖注入)来对属性进行赋值,实现面相接口编程

spring通过AOP(面向切面编程)可以为某一类对象 进行监督和控制(也就是 在调用这类对象的具体方法的前后去调用你指定的 模块)从而达到对一个模块扩充的功能。

 

spring容器

Bean 是 Spring 的基本单位,在基于 Spring 的 Java EE 应用中,所有的组件都被当成 Bean 处理,包括数据源、Hibernate 的 SessionFactory、事务管理器等。

容器的基本功能:

创建bean,销毁bean,获取bean,bean依赖关系建立

 

 

spring容器也称为spring ioc容器

特点:默认采用单例的方式创建对象

 

spring容器的结构:

BeanFactory是spring容器的顶层接口定义了容器的基本功能(配置、创建、管理Bean等)

ApplicationContext是BeanFactory的子接口。也被称为应用上下文,在基本功能基础上提供更多企业级的服务,比如解析配置文本,AOP、国际化、事件支持

WebApplicationContext是ApplicationContext的子接口,该接口是专门为 Web 应用准备的,其允许从相对于 Web 根目录的路径中装载配置文件完成初始化。

 

每个接口下面都有很多实现类,提供不同功能,都可以被称为容器

总结:

spring容器是由一系列的XXXContext类来实现的

上下文的层级

Spring允许您构建多级应用程序上下文层次结构,如果当前应用程序上下文中不存在所需的bean,则会从父上下文中获取所需的bean。

比如springmvc容器中controller中可以注入进来spring容器中的service;service注入不了controller实例

 

serveltContext

tomcat启动时创建,同一个web应用的所有servlet对象共享一个serveltContext(ServletContext不是分布式的是在一个jvm一个应用中全局),serveltContext在应用全局共享。

从serveltContext中可以获取到应用的根目录名称

 

,应用名称,服务器名称,服务器版本,根据文件相对项目的路径获取文件系统路径等

我们可以往里面设置应用全局的参数。

 

ext

ApplicationContext的常用子接口:

ConfigurableApplicationContext接口

WebApplicationContext接口

 

ConfigurableApplicationContext的常用实现类:

FileSystemXmlApplicationContext类

ClassPathXmlApplicationContext类

AnnotationConfigApplicationContext类

 

FileSystemXmlApplicationContext和ClassPathXmlApplicationContext分别是根据文件系统的XML配置文件和类加载路径下的XML配置文件中配置的bean来创建bean到容器中

AnnotationConfigApplicationContext是根据注解来创建bean到容器中

 

WebApplicationContext的子接口:

ConfigurableWebApplicationContext接口

 

ConfigurableWebApplicationContext接口实现类:

XmlWebApplicationContext

AnnotationConfigWebApplicationContext

 

ConfigurableWebApplicationContext接口同时继承了WebApplicationContext和ConfigurableApplicationContext接口

 

 

WebApplicationContext

Web应用上下,WebApplicationContext继承自ApplicationContext,也是一个接口

 

ContextLoaderListener说明

我们寻常的springmvc项目会在web.xml中配置一个监听器就是ContextLoaderListener,项目启动时该监听器默认会加载/WEB-INF/applicationContext.xml作为配置文件来创建WebApplicationContext,WebApplicationContext会以键值对的形式存储在ServletContext

这里WebApplicationContext使用的实例为XmlWebApplicationContext(这个类同时实现了WebApplicationContext和ConfigurableApplicationContext)

 

传统的xml方式,我们打印出使用的容器实体类

@Autowired

protected ApplicationContext ctx;

 

System.out.println(ctx.getClass());

 

打印出的就是XmlWebApplicationContext

 

springboot中打印的是

AnnotationConfigServletWebServerApplicationContext

 

AnnotationConfigApplicationContext

该容器负责对注解方式声明的bean的创建和管理

使用AnnotationConfigApplicationContext可以实现基于Java的配置类(@Configuration标注的类)加载Spring的应用上下文。避免使用application.xml进行配置。

对于@Component标注的类也会交给AnnotationConfigApplicationContext来创建及管理

 

获取spring容器

工具类获取

ApplicationContext ac1 = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContext sc);

ApplicationContext ac2 = WebApplicationContextUtils.getWebApplicationContext(ServletContext sc);

(区别:前者在获取失败时抛出异常,后者返回null。)

 

继承自抽象类ApplicationObjectSupport

它的getApplicationContext()方法,可以方便的获取到ApplicationContext。

Spring初始化时,会通过该抽象类的setApplicationContext(ApplicationContext context)方法将ApplicationContext 对象注入。

 

继承自抽象类WebApplicationObjectSupport

说明:类似上面方法,调用getWebApplicationContext()获取WebApplicationContext

 

实现接口ApplicationContextAware

说明:实现该接口的setApplicationContext(ApplicationContext context)方法,并保存ApplicationContext 对象。

Spring初始化时,会通过该方法将ApplicationContext对象注入。

 

直接注入到ApplicationContext变量中

@Autowired

private static ApplicationContext context;

 

 

如何交给spring容器管理:

使用xml方式(bean标签)或者注解的方式声明(@Component声明类,@Bean声明方法)

 

spring容器如何注入对象:

@Resource根据名称注入

@Autowired:根据对象类型注入

 

@Autowired注解原理:

它可以被标注在构造函数、属性、setter方法或配置方法上,用于实现依赖自动注入。(放置在不同地方就表示不同时机来注入,如构造函数,就是调用构造函数的时候,属性上调用完构造函数之后,setter方法上调用set方法的时候,配置方法,调用配置方法的时候)

通过反射来进行注入

在使用@Autowired时,首先在容器中查询对应类型的bean

  • 如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
  • 如果查询的结果不止一个,那么@Autowired会根据名称来查找。
  • 如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false

 

@Autowired标注在属性上也不需要设置set和get方法

当使用@Autowired注解进行依赖注入时,Spring会根据依赖的类型或名称来查找对应的Bean,并调用相应的构造函数进行依赖注入。如果存在无参构造函数,则会调用无参构造函数进行依赖注入;如果不存在无参构造函数,则会调用带参构造函数进行依赖注入。

 

通过有参构造函数注入bean:

@Service
public class MyService {
    private MyDependency myDependency;

    @Autowired
    public MyService(MyDependency myDependency) {
        this.myDependency = myDependency;
    }
}

通过setter方式注入bean:

public class UserServiceImpl implents UserService{
     private UserDao userDao;
     
     @Autowire
     public serUserDao(UserDao userDao){
         this.userDao = userDao;
     }
 }

springMVC容器

DispatcherServlet是springMVC的前端控制器,该servlet初始化的时候会创建springMvc容器

 

应用启动springMVC容器创建,springmvc容器是WebApplicationContext容器的子容器

Spring容器的启动是先于SpringMVC容器的

springMVC容器负责管理@Controller标注的类及视图解析器相关的类的实例创建及管理

Spring容器中存放着mapper代理对象,service对象,SpringMVC存放着Controller对象。

ContextLoaderListener启动了spring容器,DispatcherServlet启动了springMVC容器

 

IOC介绍

Inversion of Control,英文缩写为IoC,汉译为控制反转

控制反转是面向对象编程中的一种设计思想,用来减低计算机代码之间的耦合度。

代码间对其他对象的依赖不直接去主动创建对象使用,而是被动的接受容器注入过来的对象使用。

 

控制:所依赖的对象或资源的控制权

反转:变主动获取对象为被动接受对象或资源,即获取对象或资源的方式反转了

 

spring中的ioc是把对象交给spring容器进行管理,注入到需要的地方

 

DI和IOC:

DI是依赖注入,也就是把由容器管理的对象注入到需要它的地方,它是IOC的另一种说法,都是同一个意思,ioc的描述偏向与思想,DI的描述偏向于过程和实现。

 

spring的IOC:

由Spring容器来控制对象的生命周期,利用spring容器来注入对象

bean对象的的创建是通过反射来创建然后放入到容器中的

 

ioc如何控制对象的生命周期:
1. 创建实例:根据配置信息或注解找到spring容器管理的类通过反射实例化Bean。
2. 初始化实例:调用Bean的初始化方法进行初始化。
3. 使用实例:将实例注入到需要的地方,供应用程序使用。
4. 销毁实例:在容器关闭时,调用Bean的销毁方法(destroy方法)进行清理工作。
 
依赖注入:
依赖注入的实现原理主要是通过反射机制实现的。Spring容器在实例化Bean时,会通过反射来查找Bean的依赖关系,并将依赖的对象注入到Bean中。

 

spring创建对象的方式

构造器方式(调用构造方法)

静态工厂方式(加载完静态工厂类,使用类的静态方法来new出对象)

实例工厂方式(实例化工厂类后,使用非静态静态方法来new出对象)

 

什么时候进行依赖注入

对与非懒加载的bean是spring容器启动时完成注入(springboot中默认是非懒加载的)

对与懒加载的bean是首次使用依赖对象的时候进行注入

 

如果单个类想要配置成懒加载就在具体依赖的类上加上@Lazy注解,代表容器启动的时候不创建对象,使用的时候才进行创建对象

如果

 

 

依赖注入的内容

service层如果未使用aop进行动态代理注入的是接口的实现类(如TestServiceImpl),如果使用了动态代理注入的是动态代理类(如com.sun.proxy.$Proxy18)

 

依赖注入的方式

spring依赖注入方式:

  • Set方法注入(执行完构造方法后注入)
  • 有参构造器注入(执行构造方法的时候注入)
  • 属性注入(执行完构造方法后注入)

 

DI的实现

不管是xml实现方式还是注解的实现方式都要通过反射进行注入实例

 

AOP介绍

概念:AOP就是面向方面的编程,

方面:贯穿到系统的各个模块中的系统一个功能就是一个方面,

比如,记录日志,统一异常处理,事务处理,权限检查,这些功能都是软件系统

的一个面,而不是一点,在各个模块中都要出现。

面向方面编程:把系统的一个方面的功能封装成对象的形式来处理

怎么进行面向方面编程:把功能模块对应的对象作为切面嵌入到原来的各个系统模块中,

采用代理技术,代理会调用目标,同时把切面功能代码(对象)加入进来,所以,用spring配置代理对象时只要要配两个属性,分别表示目标和切面对象。

 

springAop原理:

AOP原理:利用动态代理实现对目标方法的增强,完成事务管理,日志管理,安全管理,权限管理等。(如果代理类实现了接口就使用jdk动态代理实现代理类,如果没有实现接口就使用cglib动态代理实现)

jdk动态代理基于接口创建代理对象,CGLIB通过继承目标类来创建代理对象,功能相似,实现机制不同。

 

OOP和AOP区别:

OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装

而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。简而言之就是把逻辑各部分分离。

 

spring已经封装好的aop常用的有那些

@Transactional:用于声明事务性方法。(在原有方法上增加了事务开启,事务提交,事务回滚等功能)
@Async:用于声明异步方法。(方法调用时创建一个新的线程来执行方法)
@Cacheable:用于声明缓存方法(方法调用前先看缓存中是否有数据,有的话就不再调用原始方法)。
@Retryable:用于声明可重试方法(当方法抛出异常时,代理对象会捕获这个异常,并根据配置的重试策略决定是否重新执行该方法。)。

 

@Async注解说明:

为了使用 @Async 注解,你需要在 Spring 的配置中启用异步执行支持,并配置一个或多个 TaskExecutor。此外,默认情况下,@Async 方法不会等待异步操作完成就返回,而是立即返回一个 Future 对象。如果需要等待异步操作完成并获取结果,你可以调用 Future 的 get() 方法。

import org.springframework.context.annotation.Configuration;  
import org.springframework.scheduling.annotation.EnableAsync;  
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;  
import org.springframework.context.annotation.Bean;  
  
@Configuration  
@EnableAsync  
public class AsyncConfig {  
  
    @Bean(name = "taskExecutor")  
    public Executor taskExecutor() {  
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();  
        executor.setCorePoolSize(5);  
        executor.setMaxPoolSize(10);  
        executor.setQueueCapacity(25);  
        executor.setThreadNamePrefix("Async-");  
        executor.initialize();  
        return executor;  
    }  
}
import org.springframework.scheduling.annotation.Async;  
import org.springframework.stereotype.Service;  
  
@Service  
public class AsyncService {  
  
    @Async("taskExecutor")  
    public void asyncMethod() {  
        // 执行一些需要异步处理的任务  
        System.out.println("Async method is executing on thread: " + Thread.currentThread().getName());  
    }  
}

异步方法返回类型通常是 void 或者 Future<T>(如果你需要获取异步执行的结果)。对于返回 Future 的情况,你可以使用它来查询异步操作的状态或获取结果。

@Cacheable注解说明

在配置文件中对缓存连接信息进行配置

spring:  
  redis:  
    host: localhost  
    port: 6379  
    database: 0  
    jedis:  
      pool:  
        max-active: 10  
        max-wait: -1ms  
        max-idle: 5  
        min-idle: 0

需要在配置类上添加 @EnableCaching 注解,并对缓存管理器进行配置

@Configuration  
@EnableCaching  
public class CacheConfig {  
 
    @Bean  
    public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {  
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()  
            .entryTtl(Duration.ofMinutes(10)) // 设置缓存的过期时间  
            .disableCachingNullValues(); // 不缓存空值  
 
        RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory)  
            .cacheDefaults(config)  
            .build();  
 
        return cacheManager;  
    }  
}

value或cacheNames指定缓存的名字,key指定缓存的键

import org.springframework.cache.annotation.Cacheable;  
import org.springframework.stereotype.Service;  
  
@Service  
public class UserService {  
  
    @Cacheable(value = "users", key = "#id")  
    public User getUserById(Long id) {  
        // 模拟一个耗时的数据库查询操作  
        return performDatabaseLookup(id);  
    }  
  
    private User performDatabaseLookup(Long id) {  
        // 这里应该是实际的数据库查询代码  
        // 为了示例,我们只是简单地返回一个模拟的 User 对象  
        return new User(id, "User" + id);  
    }  
}
@Retryable注解说明

你的配置类中,使用 @EnableRetry 注解来启用 Spring Retry。

import org.springframework.retry.annotation.EnableRetry;  
import org.springframework.context.annotation.Configuration;  

@Configuration  
@EnableRetry  
public class RetryConfig {  
    // ... 其他配置 ...  
}

在需要重试的方法上使用 @Retryable 注解,并指定需要重试的异常类型。你还可以设置其他参数,如最大重试次数、回退策略等。

import org.springframework.retry.annotation.Retryable;  
import org.springframework.stereotype.Service;  

@Service  
public class RetryableService {  

    @Retryable(value = {SomeException.class}, maxAttempts = 3, backoff = @Backoff(delay = 1000))  
    public void retryableMethod() {  
        // 可能会抛出 SomeException 的方法逻辑  
    }  
}

如果 retryableMethod 方法抛出 SomeException 异常,Spring Retry 会尝试重新执行该方法,最多重试 3 次,每次重试之间等待 1 秒。

如果达到最大重试次数仍然失败,代理对象可以选择抛出异常或执行其他回退逻辑(通过 @Recover 注解定义)。

AOP优点

业务功能也通用的功能松耦合,可以对通用功能统一管理维护

避免在业务中还要考虑加入通用功能带来的复杂性,代码清晰,提升开发效率

Aop中的一些概念

切面 Aspect

切面是一个类如:事务、日志、安全性的框架,权限等类就是切面

通知 Advice

切面中的方法就是通知

连接点 JoinPoint

客户端调用的方法就是连接点

切入点 Pointcut

只有符合切入点的条件,才能让通知和目标方法结合在一起,满足一定条件才会执行目标方法,这里的条件表达式就是切入点

目标对象 Target

目标对象就是被代理对象也就是target

AOP代理

AOP代理就是代理对象

织入:

形成代理对象方法体的过程

 

通知方式:

  • 前置通知: 在目标方法执行之前执行
  • 后置通知: 在目标方法执行之后执行,可以获取目标方法的返回值,当目标方法遇到异常,不执行
  • 最终通知: 无论目标方法是否遇到异常都会执行,相当于代码中的finally
  • 异常通知: 能获取目标方法抛出的异常
  • 环绕通知: 可以同时控制目标方法执行前后的逻辑

注解方式实现aop功能实例

// 1. 创建自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
}

// 2. 创建切面类
@Aspect
@Component
public class CustomAspect {
    // 带有com.example.CustomAnnotation注解的方法之前执行。
    @Before("@annotation(com.example.CustomAnnotation)")
    public void beforeAdvice() {
        System.out.println("Before advice executed");
    }
}

// 4. 启用AspectJ自动代理并扫描切面类
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "com.example")

// 5. 在需要应用AOP的方法或类上添加自定义注解
@Service
public class MyService {
    
    @CustomAnnotation
    public void myMethod() {
        System.out.println("Method executed");
    }
}

AOP配置方式

xml方式,注解方式

<!-- 引入目标类和切面-->
   <bean id="personDao" class="com.itheima09.spring.aop.xml.transaction.PersonDaoImpl"></bean>
   <bean id="transaction" class="com.itheima09.spring.aop.xml.transaction.Transaction"></bean>
   <!-- aop:config的配置 -->
   <aop:config>
       <!-- 切入点表达式,id为标示符 -->
       <aop:pointcut expression="execution(* com.itheima09.spring.aop.xml.transaction.PersonDaoImpl.*(..))" id="perform"/>
       <!-- ref指向切面-->
       <aop:aspect ref="transaction">
           <!--
           前置通知  在目标方法输出之前执行 method 前置通知的名字 pointcut-ref 指向切入点表达式-->
           <aop:before method="beginTransaction" pointcut-ref="perform"/>
           <aop:after-returning method="commit" pointcut-ref="perform"/>
       </aop:aspect>
   </aop:config>

 

 

注解方式:

@Aspect 标注在切面类上

如:

@Component("transaction")
@Aspect//说明该注解标注的类是一个切面类
public class Transaction {
	@Pointcut("execution(* com.itheima09.springaop.annotation.transaction.PersonDaoImpl.*(..))")
	private void aa(){} //方法标签(没有实际功能的方法)    修饰符最好是private 返回值必须是void
	
	@Before("aa()")
	public void beginTransaction(){
		System.out.println("begin transaction");
	}
	
	@AfterReturning(value="aa()",returning="ex")
	public void commit(JoinPoint joinPoint,Object ex){
		System.out.println("commit");
	}
}

 

AOP常用的注解

@Aspect :标注为切面类

@Before:标注为前置通知方法

@AfterReturning:标注为后置通知方法

@After:标注为最终通知方法

@Around:标注为环绕通知方法

@AfterThrowing标注为异常通知方法

@Pointcut:标注切入点

@Order:表示织入顺序,如果有多个切面类,用改参数指定执行的顺序,值越小,优先级越高

 

spring的注解aop功能原理

当类被加载到内存中,通过反射机制可以获取类的注解信息,当Spring容器初始化时,会扫描类路径下的所有类,检查aop相关的注解信息,通过反射获取到相关的方法,之后就是通过动态代理生成代理类进行处理。

spring启动过程

Spring的启动过程其实就是Spring IOC容器的启动过程。

tomcat启动会加载web.xml文件并根据web.xml文件中配置类实例化监听器,过滤器,servlet等;在web.xml中配置有ContextLoaderListener监听器,所以项目启动时会实例化ContextLoaderListener,该监听器实例化后就进行spring容器的创建和启动,它会创建WebApplicationContext实例(这是一个接口,其实际默认实现类是XmlWebApplicationContext。这个就是Spring IOC的容器),加载配置的spring配置文件(该listener默认加载/WEB-INF/applicationContext.xml作为配置文件,如果web.xml中的context-param指定的初始化参数中有contextConfigLocation参数就会以指定位置的spring配置文件为准,context-param先于listener执行),实例化配置文件中配置的bean,之后把spirng容器放入到了ServletContext

 

总结:tomcat启动时加载web.xml实例化ContextLoaderListener,该监听器创建spring容器,实例化配置文件中的bean,把spring容器放入servletContext(ServletContext是应用全局的容器,放到它里面方便获取spring容器)

 

主要分为三个阶段:

spring容器的初始化:主要是创建spring容器

Bean的实例化:bean的初始赋值,bean的构造函数调用(实例化过程包含了我们基本bean的赋默认值,初始值等过程)

Bean的初始化:依赖的注入和执行一些用户自定义的初始化逻辑。(是spring定义的bean初始化,并不是基本的bean的初始化,基本bean的初始化在bean的实例化过程中)

 

springMVC启动过程

web.xml中配置有DispatcherServlet,如果该servlet的load-on-startup配置的大于0,tomcat启动时会实例化DispatcherServlet,该servlet初始化时创建springMVC容器,指定Spring容器为SpringMvc的父容器,初始化处理器映射器,处理器适配器,视图解析器等组件

 

spring单例Bean

Spring单例Bean与单例模式的区别在于它们关联的环境不一样,单例模式是指在一个JVM进程中仅有一个实例,而Spring单例是指一个Spring Bean容器(ApplicationContext)中仅有一个实例。

Spring的单例Bean是与其容器(ApplicationContext)密切相关的,所以在一个JVM进程中,如果有多个Spring容器,即使是单例bean,也一定会创建多个实例

 

Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例

 

spring Bean的作用域或者范围

作用域

描述

singleton

在spring IoC容器仅存在一个Bean实例,以单例方式存在,默认值。

prototype

每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()。多例

request

每次HTTP请求都会创建一个新的Bean,该作用域仅适用于web的Spring WebApplicationContext环境。

session

同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。该作用域仅适用于web的Spring WebApplicationContext环境。

application

限定一个Bean的作用域为ServletContext的生命周期。该作用域仅适用于web的Spring WebApplicationContext环境。

 

spring常用注解

@Transactional声明式事务的注解

@Component:标注一个普通的spring Bean类。

@Controller:标注一个控制器组件类。

@Service:标注一个业务逻辑组件类。

@Repository:标注一个DAO组件类。

@Autowired根据类型注入

@Resource根据名称注入

@RequestMapping 用来定义访问的URL,放在类或方法上

@PathVariable表示方法参数绑定到地址URL的模板变量

如:@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)  
public String findOwner(@PathVariable String ownerId, Model model) { }

@RequestParam 用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,进行参数绑定,通常用于GET请求,post请求在url中带参数也可以使用

包含3个配置 @RequestParam(required = ,value="", defaultValue = "") 

required :参数是否必须,boolean类型,可选项,默认为true 

value: 传递的参数名称,可选项,如果有值,对应到设置方法的参数 

defaultValue:参数没有传递时为参数默认指定的值 

@RequestBody 一般用于处理非 Content-Type: application/x-www-form-urlencoded编码格式的数据,比如:application/json、application/xml等类型的数据。通过springmvc提供的HttpMessageConverter接口将读到的内容转换为json、xml等格式的数据并绑定到controller方法的参数上。不能处理get请求

@RestController 用于处理HTTP请求,@RestController= @Controller +@ResponseBody

@PropertySource 加载指定的properties或yml配置文件

@ImportResource  加载spring的配置文件

@Value 给属性注入值

 

@Scope

 @Scope中可以指定如下值:

       singleton:定义bean的范围为每个spring容器一个实例(默认值)

       prototype:定义bean可以被多次实例化(使用一次就创建一次)

       request:定义bean的范围是http请求(springMVC中有效)

       session:定义bean的范围是http会话(springMVC中有效)

       global-session:定义bean的范围是全局http会话(portlet中有效)

@Configuration将类标注为配置类,类似xml中beans标签

@Bean将方法返回的bean添加到容器中

 

springmvc常用注解

@Controller控制器定义

@ReqestMapping 在类前面定义,则将url和类绑定。在方法前面定义,则将url和类的方法绑定

@RequestParam,将指定的请求参数付给方法中形参

@SessionAttributes将指定key的键值对放入session中

@ModelAttribute放入或取出request域中的值

@CookieValue获取cookie信息

@PathVariable,获取url中的指定变量值

@RequestBody

@ResponseBody

 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。

 

使用时机:

      返回的数据不是html标签的页面,而是其他某种格式的数据时(如json、xml等)使用;

要返回xml可以在bean的实体类上用@XmlRootElement,@XmlElement(name = "hot_car")等xml的注解标注,@ResponseBody不需要特殊处理

@RequestHeader获取请求头信息

 

 

@ReqestMapping注解说明:

在Spring MVC 中使用 @RequestMapping 来映射请求

 

spring中的单例bean是线程安全的吗

大部分的Spring bean并没有可变的状态(比如Service类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话,就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用域由“singleton”变更为“prototype”。

 

spring如何处理线程并发问题

spring对一些有状态的bean的采用ThreadLocal进行处理,解决线程安全问题。

 

spring与threadlocal

ThreadLocal是线程的局部变量,多线程操作时不会影响到ThreadLocal中的值,使用ThreadLocal可以避免线程安全问题

ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。

ThreadLocal为每一个线程提供一个独立的变量副本,从而隔离了多个线程对访问数据的冲突。

同步机制采用了“以时间换空间”的方式:访问串行化,对象共享化。ThreadLocal采用了“以空间换时间”的方式:访问并行化,对象独享化。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

 

Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全的“状态性对象”采用ThreadLocal进行封装,让它们也成为线程安全的“状态性对象”,因此有状态的Bean就能够以singleton的方式在多线程中正常工作了。

 

每个事务的上下文都应该是独立拥有数据库的connection连接的,否则在数据提交回滚过程中就会产生冲突。从数据库连接池拿到连接后,放到threadLocal中,事务提交或回滚后删除。

 

 

spring和springmvc的注解扫描

我们使用注解的时候,一般都是在spring配置文件中配置注解扫描dao层、service层的包,在springMVC配置文件中配置注解扫描controller

spring的配置

<context:component-scan base-package="com.xgss.ssm">
     <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

springmvc的配置

<context:component-scan base-package="com.xgss.ssm.controller" />

 

如果只用spring配置注解扫描@Controller不会处理请求

如果只在springmvc中扫描注解事务会失效

 

spring项目启动时执行自定义逻辑

java自身的启动时加载方式:
static代码块:static静态代码块,在类加载的时候即自动执行。
构造方法:在对象初始化时执行。
 
Spring启动时加载方式:
@PostConstruct注解
PostConstruct注解使用在方法上,这个方法在对象依赖注入初始化之后执行。
ApplicationRunner和CommandLineRunner
SpringBoot提供了两个接口来实现Spring容器启动完成后执行的功能,两个接口分别为CommandLineRunner和ApplicationRunner。
 
这两个接口需要实现一个run方法,将代码在run中实现即可。这两个接口功能基本一致,其区别在于run方法的入参。ApplicationRunner的run方法入参为ApplicationArguments,为CommandLineRunner的run方法入参为String数组。
Order注解
当有多个类实现了CommandLineRunner和ApplicationRunner接口时,可以通过在类上添加@Order注解来设定运行顺序。
Spring应用启动过程中,肯定是要自动扫描有@Component注解的类,加载类并初始化对象进行自动注入。加载类时首先要执行static静态代码块中的代码,之后再初始化对象时会执行构造方法。
 
在对象注入完成后,调用带有@PostConstruct注解的方法。当容器启动成功后,再根据@Order注解的顺序调用CommandLineRunner和ApplicationRunner接口类中的run方法。
 
因此,加载顺序为static>constructer>@PostConstruct>CommandLineRunner和ApplicationRunner.

 

spring中的设计模式

(1)工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;

(2)单例模式:Bean默认为单例模式。

(3)代理模式:Spring的AOP功能用到了动态代理;

(4)模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。

(5)观察者模式:定义一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现--ApplicationListener。

 

讲讲代理模式

静态代理:

代理类和被代理类实现同一个接口,代理类调用被代理类方法,并提供额外的方法。

public interface PersonDao {
	public void savePerson();
}
public class PersonDaoImpl implements PersonDao {
	public void savePerson() {
		System.out.println("savePerson");
	}
}
public class PersonDaoProxy implements PersonDao {
	private PersonDao personDao;
	private Transaction transaction;
	public PersonDaoProxy(PersonDao personDao,Transaction transaction){
		this.personDao=personDao;
		this.transaction=transaction;
}
@Override
public void savePerson() {
	this.transaction.beginTransation;
	personDao.savePerson();
	this.transaction.commit();
}
}

缺点:

一个代理类只为一个接口服务,需要代理的类都需要独立建立代理类

如果接口中的方法很多,那代理类中的方法也会同样多,而且会有很多的重复代码。

动态代理:

动态代理比静态代理更加灵活不需要事先创建好代理类,而是需要代理的时候动态创建代理类

它的核心是 java.lang.reflect.Proxy代理类,该类位于reflect反射包下,可知动态代理当中是用了反射的技术来实现的。

pring的DI依赖注入和aop切面编程都是通过动态代理实现的

jdk动态代理

public class PersonDaoTest {
		public void testJDKProxy(){
		Object target = new PersonDaoImpl();
		Transaction transaction = new Transaction();
PersonDaoInterceptor interceptor = new PersonDaoInterceptor(target, transaction);
		
		PersonDao personDao = (PersonDao)Proxy.newProxyInstance(
					target.getClass().getClassLoader(), 
					target.getClass().getInterfaces(), interceptor);
		personDao.savePerson();
	}}

jdk的动态代理需要依赖接口实现,如果有一些类没有实现接口,就不能使用jdk的动态代理。

cglib动态代理:

它的原理是对指定的目标类生产它的一个子类,并覆盖其中的方法实现增强。因为采用的继承,所以final类不能够实现。

public class PersonDaoInterceptor implements MethodInterceptor{
	private Object target;
	private Transaction transaction;
	
	public PersonDaoInterceptor(Object target, Transaction transaction) {
		this.target = target;
		this.transaction = transaction;
	}

	public Object createProxy(){
		Enhancer enhancer = new Enhancer();
		//设置代理类的父类是目标类
		enhancer.setSuperclass(target.getClass());
		enhancer.setCallback(this);

		return enhancer.create();
	}
	public Object intercept(Object arg0, Method method, Object[] arg2,
			MethodProxy arg3) throws Throwable {
			this.transaction.beginTransaction();
			method.invoke(target, arg2);
			this.transaction.commit();
		return null;
	}}

Spring AOP中的代理根据被代理对象是否实现了接口选择不同的生成代理对象的方式,即jdk的动态代理和cglib的动态代理

Servlet介绍

Servlet本质上是实现了Servlet接口的Java类,主要用于获取客户端请求,处理请求和响应请求。

Servlet是mvc的基础,市场上任何一个mvc的框架都是servlet发展过来的.如主流的struts和springMVC

Servlet的优缺点

servlet是mvc框架的基础

缺点:

servlet配置繁琐,没写一个servlet就要在web.xml中配置,会导致web.xml内容太多。

 servlet具有容器依赖性,不利于单元测试;必须启动服务器才行。

都用一个web.xml文件,不利于分组开发。

speingmvc

SpringMVC介绍

Spring MVC 是Spring框架中的一个模块。主要用于接收客户端请求调用业务层处理请求响应客户端请求

SpringMVC原理

第一步:客户端发起请求到前端控制器(DispatcherServlet)

第二步:前端控制器请求HandlerMapping查找 Handler

可以根据xml配置、注解进行查找

第三步:处理器映射器HandlerMapping向前端控制器返回Handler

第四步:前端控制器调用处理器适配器HandlerAdapter去执行Handler

第五步:处理器适配器去执行Handler

第六步:Handler执行完成给适配器返回ModelAndView

第七步:处理器适配器向前端控制器返回ModelAndView

ModelAndView是springmvc框架的一个底层对象,包括 Model和view

第八步:前端控制器请求视图解析器View resolver去进行视图解析

根据逻辑视图名解析成真正的视图(jsp)

第九步:视图解析器向前端控制器返回View

第十步:前端控制器进行视图渲染

视图渲染将模型数据(在ModelAndView对象中)填充到request域

第十一步:前端控制器向用户响应结果

 

DispatcherServlet

被称为前端控制器,是mvc整个流程的控制中心

继承了 HttpServlet 这个类, HttpServlet 是servlet技术规范中专门用于处理http请求的servlet,所以它是处理请求处理的入口

springMVC统一异常处理

编写统一的异常处理handler,类上使用@ControllerAdvice注解,方法上使用 @ExceptionHandler注解并标明要使用的异常类如:@ExceptionHandler(BusinessException.class)

这样没有被try catch的方法抛出的异常就会在@ExceptionHandler的value找对应的异常找到就调用下面的方法进行被处理

其他会用到的注解

@InitBinder 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器(处理请求参数的绑定)

@ModelAttribute 把值绑定到Model中,使全局@RequestMapping可以获取到该值

 

启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,都会作用在 被 @RequestMapping 注解的方法上。

<context:component-scan/>作用

注解扫描器,把标记为@Component的类,添加到spring的bean工厂中去(省去了配置文件中写bean定义了),@Repository,@Service,@Controller,他们都是被@Component标记的,所以也会被自动扫描。

这些注解在spring的后续版本中会不断添加不同的功能

<mvc:annotation-driven />作用

向spring的bean工厂中,注册各种映射器,各种适配器,各种异常解析器,向适配器中初始化各种转换器等。根据header中Content-Type属性了解请求体编码方式。然后决定使用什么转换器。

Content-Type

指定post提交方式请求体编码方式

如:

Content-Type: application/x-www-form-urlencoded

Post默认的Content-Type类型,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。key/value方式

很多时候,我们用 Ajax 提交数据时,也是使用这种方式。例如 JQuery 和 QWrap 的 Ajax,Content-Type 默认值都是「application/x-www-form-urlencoded;charset=utf-8」。

 

Content-Type:multipart/form-data

我们使用表单上传文件时,必须让 form 的 enctyped 等于这个值。这种方式一般用来上传文件,各大服务端语言对它也有着良好的支持。

 

上面提到的这两种 POST 数据的方式,都是浏览器原生支持的(form的enctype可以定义的),而且现阶段原生 form 表单也只支持这两种方式。

 

Content-Type: application/json

告诉服务端消息主体是序列化后的 JSON 字符串。直接在ajax方法中指定post提交方法,

contentType:"application/json;charset=utf-8",

 

Content-Type: text/xml

告诉服务端消息主体是序列化后的xml字符串。

 

mime类型

MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准。

常用的mime类型

类型/子类型 扩展名

image/jpeg jpe

image/jpeg jpeg

image/jpeg jpg

text/css css

text/html htm

text/html html

text/html stm

text/plain txt

等,w3c手册中有

springMVC如何存取数据的

把数据放到model中把视图放入view,中,返回modelAndView利用el表达式来取数据

springMVC中拦截器

implements HandlerInterceptor,实现该接口

在配置文件中配置对某种mapping拦截或者对所有mapping拦截

SpringMVC实现文件上传

表单enctype="multipart/form-data",method="post",<input type="file",

导入依赖

在spring的配置文件中配置文件上传解析器CommonsMultipartResolver

Controller中

利用MultipartFile file来接收上传的文件,利用file能够获得文件名,及保存到指定文件等

(File targetFile = new File(path, fileName);file.transferTo(targetFile);)

springmvc中Controller可以返回的类型

ModelAndView,String(返回逻辑视图名),redirect重定向,forward请求转发,返回void

 

在controller方法形参上可以定义request和response,使用request或response指定响应结果:

 

springmvc默认参数绑定支持的类型

基本数据类型,pojo,Model/ModelMap,HttpServletRequest,HttpServletResponse,HttpSession

 

Controller绑定时间参数

要给参数说明时间格式化格式

@DateTimeFormat(pattern = "yyyy-MM-dd") Date startTime

如果是用对象接收参数,要在属性上面指定格式化格式

@DateTimeFormat(pattern = "yyyy-MM-dd")

private Date startTime;

 

如果不指定,该参数的传递会因为类型错误而调用接口报400

 

@Controller为什么不能交给spring容器

@Controller标注的类的包是在springmvc的配置文件中配置扫描的,在spring配置文件中会提出掉

因为解析客户端请求

因为在解析@ReqestMapping解析过程中,只会springmvc容器中的类进行解析该注解,然后生成handler;不会对spring去容器中查找,所以如果配置到spring容器中的话会报404找不到

struts2

struts2实现文件上传

表单enctype="multipart/form-data",method="post",<input type="file",

导入依赖

在action中写上对应属性及get/set方法,如upload,uploadFileName,uploadContentType,就可以得到上传的文件,文件名,文件的MIME类型

然后把文件输出就可以了

struts2介绍

struts2是应用于表现层的mvc框架,模型由实现业务逻辑的JavaBean构成,控制器由ActionServlet和Action来实现,视图由一组Jsp文件构成。

 

struts2编写action的方式

一种编写普通的pojo

一种实现Action接口

一种继承ActionSupport

由于ActionSupport本身继承了许多的类,利于编写代码,所以一般都是继承ActionSupport

struts2工作原理

struts2工作原理是:

当服务器启动的时候,完成struts的初始化操作,加载各种配置文件包括struts.xml文件,启动过滤器。

浏览器访问action,被web.xml中配置匹配,执行StrutsPrepareAndExcuteFilter过滤器,该过滤器根据请求url和struts.xml文件找到action类

然后实例化action对应的类

顺序执行action中配置的拦截器(如果有的话)

执行action中方法,执行结果集,倒序执行拦截器

清空struts2容器的数据环境。

struts2的结果集

struts2的结果集,是在struts.xml中用<result>标签来配置结果,常用的结果类型:

dispatcher(转发到jsp)、chain(转发到action)、redirect(重定向到jsp)、redirectAction(重定向到action)。默认类型时dispatcher。

根据标签name,跟方法进行匹配,根据type确定结果集类型

重定向涉及到两次请求第二次请求不会携带第一次请求里面保存的内容

重定向是客户端的行为涉及到两次请求,请求转发是服务端行为涉及到一次请求

struts2是怎么存取数据的

把数据放入值栈中,利用OGNL表达式来获取值栈中的内容

值栈对象是在放在request域中的,

值栈包括对象栈和map栈,对象栈是一个arrayList,map栈是一个map

对象栈的存放:

ActionContext.getContext().getValueStack().push(“aaa”);放到栈顶

pop是弹出(也就是删除),peek方法是提取

如果放入栈顶的是对象,可以用setParameter方法来修改对象属性的值

Map栈的存放:

ActionContext.getContext().put(“name”,”aaa”);

数据的取:

利用OGNL表达式,<s:property>标签,通过value指定要输出的内容来源

 

struts2中拦截器

struts2默认使用了很多的拦截器,自定意拦截器的话实现Interceptor接口,然后在配置文件中配置即可

 

struts2中常用的标签

s:prototype,用于输出值

 

 

Iterator标签,#表示从map栈中取key为persons的对象,这里是List对象,所以要遍历

放request域中取List的方法

map栈放map

<s:form>标签<s:textfield><s:select>等,

表单中的value属性写ognl表达式应该加上百分号:value=”%{ognl表达式}%”

一个请求在 Struts2 框架中的处理大概分为以下几个步骤:

        (1) 客户端初始化一个指向 Servlet 容器(例如 Tomcat)的请求;

        (2) 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做 ActionContextCleanUp 的可选过滤器,这个过滤器对于 Struts2 和其他框架的集成很有帮助,例如:SiteMesh Plugin);

        (3) 接着 FilterDispatcher 被调用,FilterDispatcher 询问 ActionMapper 来决定这个请求是否需要调用某个 Action;

        (4) 如果 ActionMapper 决定需要调用某个 Action ,FilterDispatcher 把请求的处理交给ActionProxy;

        (5) ActionProxy 通过 Configuration Manager 询问框架的配置文件,找到需要调用的 Action 类;

        (6) ActionProxy 创建一个 ActionInvocation 的实例。

        (7) ActionInvocation 实例使用命名模式来调用,在调用 Action 的过程前后,涉及到相关拦截(Intercepter)的调用。

        (8) 一旦 Action 执行完毕,ActionInvocation 负责根据 struts.xml 中的配置找到对应的返回结果。

        返回结果通常是(但不总是,也可能是另外的一个 Action 链)一个需要被表示的 JSP 或者 FreeMarker的模版。在表示的过程中可以使用 Struts2 框架中继承的标签。在这个过程中需要涉及到 ActionMapper。

 

struts2与springmvc对比

struts2采用多例模式(要属性驱动/模型驱动来把表达的值传递给成员变量,单例会使数据不安全),springmvc一般采用单例模式(只要在handler中不用属性),所以springmvc运行速度更快

struts2需要配置的信息比较多,需要为每一个action配置结果集,springmvc直接用注解配合视图解析器就可以了。

struts2,要学习OGNL表达式,值栈等学习成本高,而springmvc直接用el表达式就可以了

mvc设计模式的特点

MVC把应用程序分成三个核心模块:模型(Model),视图(View)和控制器(Controller).他们分别处理不同的任务

视图向用户显示相关的数据,并能接受用户的输入数据,但是它不进行任何实际的业务处理.

  模型是应用程序的主体部分.模型表示业务数据和业务逻辑.一个模型能为多个视图提供数据.由于同一个模型可以被多个视图重用,所以提高了应用的重用性.  

控制器接受用户的输入并调用模型和视图去完成任务.

 

MVC的处理逻辑如下:  

 首先控制器接受用户请求,并决定应该调用哪个模型来进行处理,然后模型根据用户请求进行相应的业务逻辑处理,并返回数据. 最后控制器调用相应的视图来格式化模型,并通过视图呈现给用户

 

说说struts是如何实现MVC的 ?

 Struts采用JSP作为MVC的视图, 控制器由ActionServlet和Action类来实现. 控制器负责视图和模型之间的交互. 模型由实现业务逻辑的JavaBean或EJB组件构成,

 

RESTful

三种web服务交互方案

1、REST,采用Web 服务使用标准的 HTTP 方法 (GET/PUT/POST/DELETE) 将所有 Web 系统的服务抽象为资源,rest是一种架构设计风格,面向资源服务,基于rest实现的网络服务等价简单易用

 

2、SOAP 简单对象访问协议是交换数据的一种协议规范,是一种轻量的、简

单的、基于XML的协议。

 

3、RPC—远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。

 

如果要求设计实现简单,一般来说安全性要求不高可以考虑REST

SOAP安全性高,效率和易用性没有rest高

说一下RESTful

REST是一种设计风格,是一种开发理念,是对http的很好的诠释。

主要是对请求的url进行规范,请求方式的规范,对http的contentType规范等:

1、对url进行规范,写RESTful格式的url

非REST的url:http://...../queryItems.action?id=001&type=T01

REST的url风格:http://..../items/001

特点:url简洁,将参数通过url传到服务端

2、http的请求方式规范

不管是删除、添加、更新。。使用url是一致的,如果进行删除,需要设置http的方法为delete,同理添加。。。

 

后台controller方法:判断http请求方式

get 获取

post添加

put修改

delete删除

 

3、对http的contentType规范

请求时指定contentType,要json数据,设置成json格式的type。。

 

SpringMVC实现RESTful服务

SpringMVC原生态的支持了REST风格的架构设计。

所涉及到的注解:

@RequestMapping

@PathVariable

@ResponseBody

……

如:

@RequestMapping(value="/ viewItems/{id}"):{×××}占位符,请求的URL可以是“/viewItems/1”或“/viewItems/2”,通过在方法中使用@PathVariable获取{×××}中的×××变量。

@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。

@RequestMapping("/viewItems/{id}") 
public @ResponseBody viewItems(@PathVariable("id") String id,Model model) throws Exception{
//方法中使用@PathVariable获取useried的值,使用model传回页面
    //调用 service查询商品信息
    ItemsCustom itemsCustom = itemsService.findItemsById(id);
    return itemsCustom;
}

如果RequestMapping中表示为"/viewItems/{id}",id和形参名称一致,@PathVariable不用指定名称。

 

如何发起delete,put请求

默认情况下,PUT和DELETE请求是无法提交表单数据的。

解决方案:在web.xml中配置Spring提供的HiddenHttpMethodFilter过滤器,请求方式使用Post,在请求体中使用_method指明真正的请求参数

 

 

RESTful Web Service:

RESTful Web Service:

 

是一种常见的REST的应用,是遵守了REST风格的web服务。REST式的web服务是一种ROA(面向资源的架构)

使用cxf结合sping开发RESTful Web Service

项目导入cxf的包,web.xmle中配置CXFServlet

编写服务及实现

spring配置文件中配置暴露服务

客户端使用http请求就可以访问到

实体类会加上@XmlRootElement 实现对象和XML之间的转换

基于SOAP的webservice

webservice的三要素:SOAP、WSDL、UDDI

(UniversalDescriptionDiscovery andIntegration)

SOAP:简单对象访问协议,是基于XML语言的交换数据的一种协议规范,用于在网上传输数据。

WSDL:(WebServicesDescriptionLanguage),用来描述如何访问具体的接口

UDDI:(UniversalDescriptionDiscovery andIntegration)用来管理,分发,查询webService 。

 

restfulwebService 与webservice区别

RESTful 简化了 web service 的设计,它不再需要 wsdl ,也不再需要 soap 协议,而是通过最简单的 http 协议传输数据 ( 包括 xml 或 json) 。既简化了设计,也减少了网络传输量(因为只传输代表数据的 xml 或 json ,没有额外的 xml 包装)。

 

REST 架构的主要原则:

网络上的所有事物都可被抽象为资源(Resource)

每个资源都有一个唯一的资源标识符(Resource Identifier)

同一资源具有多种表现形式(xml、json等)

对资源的各种操作不会改变资源标识符

所有的操作都是无状态的(Stateless)

符合REST原则的架构方式即可称为RESTful

 

RESTful风格的一大特色就是使用URI来标识资源。

 

无状态性:

无状态性使得客户端和服务器端不必保存对方的详细信息,服务器只需要处理当前 Request,而不必了解前面 Request 的历史。

从而可以更容易地释放资源。

让服务器充分利用 Pool 技术来提高稳定性和性能。

 

资源操作:

GET  :      获取一个资源 
POST :    创建一个新的资源 
PUT :       修改一个资源的状态 
DELETE :删除一个资源

 

 

资源展现

XML

JSON

……

restful优势

用restful写的接口更容易理解,可读性强

数据描述简单,一般以xml,json做数据交换。

无状态,在调用一个接口(访问、操作资源)的时候,可以不用考虑上下文,不用考虑当前状态,极大的降低了复杂度。

可以非常简洁地实现webservice服务

安全性:SOAP会好于restful

 

还有其他的什么风格

从架构风格的抽象高度来看,常见的分布式应用架构风格有三种:

  • 分布式对象(Distributed Objects,简称DO)

  架构实例有CORBA/RMI/EJB/DCOM/.NET Remoting等等。

  • 远程过程调用(Remote Procedure Call,简称RPC)

  架构实例有SOAP/XML-RPC/Hessian/Flash AMF/DWR等等。

  • 表述性状态转移(Representational State Transfer,简称REST)

架构实例有HTTP/WebDAV。

 

struts2实现restful

spring mvc是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上spring3 mvc就容易实现restful url。struts2是类级别的拦截,一个类对应一个request上下文;实现restful url要费劲,因为struts2 action的一个方法可以对应一个url;而其类属性却被所有方法共享,这也就无法用注解或其他方式标识其所属方法了

有一个rest-plugin可以帮助实现restful

mybatis

mybatis介绍

mybatis是基于jdbc的持久层框架,使开发者只需要关注 SQL 本身,mybatis完成了基本的一些ORM概念,但是没有Hibernate那么完善。

mybatis工作原理

MyBatis应用程序根据XML配置文件创建SqlSessionFactory,通过SqlSessionFactory获取SqlSession。SqlSession包含了执行sql所需要的所有方法,可以通过SqlSession实例传入参数运行映射文件中的sql语句,完成对数据的增删改查和事务提交等,用完之后关闭SqlSession。

mybatis占位符

#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换,#{}可以有效防止sql注入,简单的说#{}这种方式SQL语句是经过预编译的

<select id="findUserById" parameterType="int" resultType="cn.itcast.mybatis.po.User">

select * from user where id = #{id}

</select>

 

${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。

常在模糊查询时用到,因为这时需要拼接sql串

<select id="findUserByUsername" parameterType="java.lang.String" 

resultType="cn.itcast.mybatis.po.User">

   select * from user where username like '%${value}%'

</select>

 

#{} 这种取值是编译好SQL语句再取值,这样变量部分不会作为sql的语法部分只会作为变量值在运行时使用

${} 这种是取值以后再去编译SQL语句

 

不过有时你只是想直接在 SQL 语句中插入一个不改变的字符串。比如,像 ORDER BY,你可以这样来使用(不作为用户输入参数来使用):

 

ORDER BY ${columnName}

 

或者传入表名

select * from ${prefix} ACT_HI_PROCINST where PROC_INST_ID_ = #{processInstanceId}

 

sql注入:指的是攻击者通过在应用程序的输入参数中插入恶意的SQL代码危害应用程序的安全性,SQL注入通常发生在应用程序未对用户输入数据进行充分验证和过滤的情况下,攻击者可以通过在输入框、URL参数等地方插入恶意的SQL语句,利用这些漏洞执行恶意操作。

 

mybatis的缓存机制

MyBatis的缓存机制主要包括两种类型的缓存:一级缓存(Local Cache)和二级缓存(Global Cache)。

1. 一级缓存(Local Cache):
- 一级缓存是SqlSession级别的缓存,即在同一个SqlSession中执行的查询结果会被缓存起来,避免重复查询数据库。
- 默认情况下,一级缓存是开启的,可以通过SqlSession的clearCache()方法清空一级缓存。

-在修改数据时会被自动清理

2. 二级缓存(Global Cache):
- 二级缓存是Mapper级别的缓存,即多个SqlSession共享同一个Mapper的缓存,可以跨SqlSession共享缓存数据。
- 需要在Mapper.xml文件中配置<cache>标签开启二级缓存,并在MyBatis配置文件中开启全局缓存。
- 二级缓存可以提高多个SqlSession之间的数据共享和查询性能,但需要注意缓存的更新和失效策略,避免数据不一致性。

它适用于那些读多写少的场景,因为每次更新操作都会清空缓存。对于高并发写入的场景,二级缓存可能不是最佳选择,因为它可能导致数据不一致。

通过一级缓存和二级缓存的结合使用,MyBatis能够提高查询性能,减少数据库访问次数,提升系统的性能和响应速度。

SqlSession代表了一次数据库连接会话,用于执行SQL语句、提交事务、关闭连接等操作。在同一个SqlSession中执行的数据库操作会共享同一个数据库连接和事务上下文。一个sqlSession只会对应一个事务。

一级缓存的使用条件:
1. 相同的查询语句:即相同的SQL语句和参数,才能从一级缓存中获取缓存的查询结果。
2. 相同的SqlSession:查询操作必须在同一个SqlSession中执行,才能共享同一个一级缓存。

 

使用二级缓存可能会导致在不同事务中执行相同的查询语句时,查询到的数据与数据库中的数据不一致。这是因为二级缓存是全局共享的,多个SqlSession可以共享同一个Mapper的缓存数据,而且二级缓存的更新和失效策略可能会导致数据不一致性。在使用二级缓存时,需要谨慎配置缓存的更新和失效策略,确保数据的一致性和正确性。

要使用二级缓存也需要相同的SQL语句和参数。

使用一级缓存可以会导致查询的数据跟数据库的不一致,这是因为第一次查询后其他sqlSession对数据做了更改,而一级缓存又不进行查询数据库导致查询的数据不一致。而且在可重复读的情况下及时查询了数据库也会不一致。如果要求必须一致就用程序锁或者数据库锁避免多个地方修改数据。

springboot开启二级缓存的步骤

你需要在 MyBatis 的配置文件(通常是 mybatis-config.xml)中启用全局二级缓存。你使用的是注解或 Java 配置,确保通过 Configuration 类设置 cacheEnabled 属性为 true

<settings>  
    <setting name="cacheEnabled" value="true"/>  
</settings>

对于需要使用二级缓存的映射器(Mapper),在对应的 XML 映射文件中添加 <cache/> 元素。例如:

<mapper namespace="com.example.mapper.UserMapper">  
    <cache/>  
    <!-- 其他映射语句 -->  
</mapper>

如果你使用的是注解,则需要在 Mapper 接口上使用 @CacheNamespace 注解

MyBatis 默认使用基于内存的缓存实现。如果需要,你可以通过实现 org.apache.ibatis.cache.Cache 接口来自定义缓存策略,并在 <cache/> 标签中使用 type 属性来指定你的自定义缓存实现。

<cache type="com.example.cache.MyCustomCache"/>
  1. 确保实体类实现了序列化

由于二级缓存中的数据会存储在内存或者通过序列化机制存储到其他地方,因此所有要缓存的实体类必须实现 java.io.Serializable 接口。

 

hibernate和mybatis比较

hibernate需要开发人员定义pojo与数据库表的映射,hibernate能够实现表的创建。主要思想是OR Mapping

mybatis需要开发人员定义pojo与sql中参数的映射和返回结果的映射,不能够实现表的创建。主要思想是sql Mapping

 

hibernate不需要写sql语句,只需要通过Hibernate框架提供的简单的方法就可以实现对数据库的增删改查工作。对sql语句进行优化、修改比较困难的。

mybatis的重点就是学sql语句,所以需要自己在xml文件中写sql语句。sql修改、优化比较方便。

hibernate和mybatis缓存机制比较

相同点:Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓存方案,创建适配器来完全覆盖缓存行为。

不同点:mybatis是相同的namespace共享同一个二级缓存

如何实现mapper代理

mapper代理就是我们只要写mapper接口和mapper.xml,mybatis会自动为我们创建代理对象实现功能。

使用mapper代理,需要我们写mapper.xml文件,而且要遵循一定的规范

在mapper.xml中namespace为mapper接口全名

mapper.java接口中的方法名和mapper.xml中statement的id一致

mapper.java接口中的方法输入参数类型和mapper.xml中statement的parameterType指定的类型一致。

mapper.java接口中的方法返回值类型和mapper.xml中statement的resultType指定的类型一致。

 

Mapper代理的实现是根据jdk动态代理实现的

 

mybatis配置文件

SqlMapConfig.xml,名称可以自定义,mybatis的全局配置文件

用来配置mybatis的运行环境,数据源、事务等

全局配置文件的内容和顺序

properties(属性):用来加载指定的properties文件

settings(全局配置参数):开启二级缓存、开启延迟加载。

typeAliases(类型别名):pojo的别名指定或扫描

typeHandlers(类型处理器):用于jdbc类型和java类型的转换

objectFactory(对象工厂)

plugins(插件)

environments(环境集合属性对象)

environment(环境子属性对象)

transactionManager(事务管理)

dataSource(数据源)

mappers(映射器):指定加载的xml位置

 

加载mapper.xml文件的方式

在SqlMapConfig.xml中进行指定加载mapper

单个加载:

<mappers>

<mapper resource="mybatis/CityMapper.xml"/>

</mappers>

 

如果mapper.java和mapper.xml在同一个包中可以

<mappers>

<mapper class="com.xgss.ssm.mapper.CityMapper"/>

</mappers>

或:批量加载

<mappers>

<package name="com.xgss.ssm.mapper"/>

</mappers>

 

如果不在同一个包也要批量加载可以

在sqlSessionFactory中指定加载

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:spring/sqlMapConfig.xml"/>
    <property name="mapperLocations">
        <value>classpath:mybatis/*.xml</value>
    </property>
</bean>

 

mapper.xml的输入映射和输出映射

输入映射:

parameterType:指定输入参数的类型

它支持很丰富的类型 int/integer/string/double/list/map/实体,可以用别名或类全名

parameterType可以不写,mabatis会自动识别

mapper接口中有多个参数:每个对象或参数都要加@Param注解

 

输出映射

resultType:

一般数据类型:使用别名或全类名

pojo:别名或全类名,只有查询出来的列名和pojo中的属性名一致,才能映射成功。

list:泛型的别名或全类名,如List<Employee>,填employee

map:一条就写map,多条mapper.java指定@MapKey,resultType写泛型别名或全类名

 

resultMap使用方法

如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。

 

1、定义resultMap

2、使用resultMap作为statement的输出映射类型

mybatis-plus

它在MyBatis的基础上进行了增强,但并不改变MyBatis的核心功能。

包括但不限于自动生成MyBatis的mapper接口以及对应的实现类,提供了通用的CRUD方法

mybatis-plus不提供复杂的查询功能,比如 跨表查询,子查询等。

PageHelper

PageHelper是一个MyBatis的插件,内部实现了一个拦截器,

当MyBatis启动后,它会加载这个拦截器到拦截器链中。在执行查询之前,我们使用PageHelper.startPage方法设置分页参数(如页码和每页显示的记录数)。这些分页参数会被保存在一个与当前线程绑定的ThreadLocal变量中。

当MyBatis执行查询操作时,PageInterceptor拦截器会拦截到SQL语句。它会从ThreadLocal中获取之前设置的分页参数,然后根据这些参数在原始的SQL语句后添加LIMIT子句,以形成分页查询的SQL语句。LIMIT子句的作用是限制查询结果的数量,并指定从哪一条记录开始返回,从而实现分页效果。

完成分页查询后,PageInterceptor拦截器还会自动清除ThreadLocal中存储的分页参数,以避免内存泄漏。

PageHelper通常会在执行分页查询之前执行一个COUNT查询来获取总记录数。如果条数为0就不去再limit查询了。 

hibernate

(就说简介和工作原理,然后是跟jdbc相比,跟mybatis相比)

基于Jdbc开发的开源的ORM框架,在分层结构中处于持久化层,封装对数据库的访问细节,使业务逻辑层更专注于实现业务逻辑

hibernate工作原理

原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory 3.打开Session 4.创建事务Transation 5.持久化操作 6.提交事务 7.关闭Session 8.关闭SesstionFactory

(1)hibernate如何连接数据库?

              配置文件Hibernate.cfg.xml文件中定义了和数据库进行连接的信息,包括数据库方言.jdbc驱动.用户名.密码和URL等。 Configuration 类借助dom4j的xml解析器进行xml的解析设置环境,然后使用这些环境属性来生成sessionfactory。这样sessionfactory生成的session 就能够成功获得数据库的连接。

         (2)hibernate如何进行数据库写操作?

              当保存一个pojo持久化对象时,触发Hibernate保存事件监听器进行处理。Hibernate通过映射文件获得对象对应的数据库表名以及属性对应的数据库列名,然后通过反射机制获得持久化对象的各个属性,最终组织向数据库插入新对象的SQL的insert语句。调用session.save()保存数据后这个对象会被标识为持久化状态放在session,当事物进行提交时才真正执行insert语句。

         (3)hibernate如何从数据中载入对象?

             当需要读取读取文件时,Hibernate先尝试从session缓存中读取,如果session缓存数据不存在或是脏数据并且配置了二级 缓存,Hibernate尝试从二级缓存中检索数据;否则Hibernate会根据对象类型·主键等信息组织select语句到数据库中读取,再把select结果组织成对象返回。

         (4)hibernate如何进行数据库查询操作?

              Hibernate提供SQL  HQL  Criteria查询方式。HQL是其中运用最广泛的查询方式。用户使用session.createQuery()函数以一条HQL语句为参数创建Query查询对象后,Hibernate会使用Anltr库把HQL语句解析成jdbc可以识别的sql语句。如果设置了查询缓存,那么执行Query.list()时,Hibernate会先对查询缓存进行查询,如果查询缓存不存在,在使用select语句查询数据库。

hibernate的3种对象状态

临时状态,持久化状态,脱管状态

临时状态(对象刚创建出来还没有sessinon保存到缓存与没有与数据库中数据对应),持久化状态(session的缓存中数据库中都有该对象),游离状态(一般由持久化状态转变过来,session缓存中没有该对象)

 

ORM框架

orm表示对象关系映射

是一种为了解决对象与关系数据库之间的互相不匹配的现象技术

ORM可以按照面向对象的思想来操作关系数据库中的数据。

 

hibernate的一级缓存和二级缓存

默认支持一级缓存不需要配置

一级缓存是session缓存

当session开启的时候,一级缓存起作用,当session关闭的时候,一级缓存销毁了

Session的缓存存放的是当前线程私有数据

一级缓存提供了一个临时存放对象的一个内存结构,当hibernate对对象进行操作的时候,仅仅改变的是对象的属性,改变的是一级缓存中的对象的属性,在session.flush之前的代码可以任意写,因为这个时候,并没有和数据库交互。当执行session.flush的时候,hibernate会检查一级缓存中的对象的情况,向数据库发出insert或者update语句

 

二级缓存:

1、是sessionFactory级别的缓存

2、存放的是公有数据:共享数据(所有session共享)

3、二级缓存的生命周期是随着hibernate容器启动就开了,hibernate销毁,结束。

4、Hibernate本身对二级缓存没有提供实现,是借助第三方插件实现的。

特点

公有数据的特征:

1、一般情况下保持不变

2、所有的人都能访问

3、访问的频率比较高

4、安全性不是特别高的数据

 

通过配置需要把那些类加入到二级缓存,查询的时候会放入到二级缓存

 

mybatis的一级缓存和二级缓存跟hibernate差不多,也是默认支持一级缓存,二级缓存需要在配置文件中配置,也是session级别和sessionFactory级别(mapper级别),二级缓存的作用域是mapper的同一个namespace

 

 

mybatis是如何管理session和cache的

 

posted @ 2023-02-02 09:52  星光闪闪  阅读(107)  评论(0)    收藏  举报