一.java的SPI机制
1.java提供的一套用来被第三方实现或扩展的接口,SPI的作用就是为这些被扩展的接口寻找实现类
2.SPI的实现
1)创建两个类,实现接口
1.MianTiao.java
package com.hhh.spi.impl;
import com.hhh.spi.IEat;
public class MianTiao implements IEat {
@Override
public void eat() {
System.out.println("chi miantiao");
}
}
2)MiFan.java
package com.hhh.spi.impl;
import com.hhh.spi.IEat;
public class MiFan implements IEat {
@Override
public void eat() {
System.out.println("chi mifan");
}
}
2)创建接口
3)在resource下创建文件夹:META-INF/services,在其文件夹下创建以接口全路径命名的文件,文件中写接口的实现类的全路径
4)新建测试类,使用ServiceLoader.load加载实现类
5)运行程序,查看效果
二.无xml创建web工程
1.ServletContainerInitializer接口的作用
web容器启动的时候,会利用SPI机制在classpath下的META-INF/services/javax..servlet.ServletContainerInitializer这个文件找到工程中的此接口实现类,并执行onStartup方法
2.在pom文件中添加依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<!--这个依赖只在编译阶段有效-->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>7.0.47</version>
</dependency>
2.新建ServletContainerInitializer实现类WebServletContainerInitializer.java
package com.hhh.config;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import java.util.Set;
public class WebServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
System.out.println("this is run");
}
}
3.在META-INF/service目录下新建以ServletContainerInitializer接口全路径命名的一个文件,其内容为实现类的全路径,如图所示
4.配置tomcat,运行tomcat,查看效果
三.配置servlet和filter(失败)
1.新建一个servlet的包,用来配置servlet
在onStartup方法中注册servlet,filter等,使用ServletContext这个方法参数
1.新建MyServlet.java类,继承接口HttpServlet
package com.hhh.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().print("my servlet");
}
}
2.在WebServletContainerInitializer.java类中注册servlet
(我报红了,有错误,先放着)
package com.hhh.config;
import com.hhh.servlet.MyServlet;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import java.util.Set;
//ServletRegistration
public class WebServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
System.out.println("this is run");
ServletRegistration.Dynamic dynamic= servletContext.getClass("my",MyServlet.class);
dynamic.addMapping("/my");
}
}
3.运行程序,查看效果
1.新建一个filter的包,用来配置filter
1.新建MyFilter.java类,继承接口HttpServlet
package com.hhh.filter;
import javax.servlet.*;
import java.io.IOException;
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("filter before");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("filter after");
}
@Override
public void destroy() {
}
}
2.在WebServletContainerInitializer.java类中注册filter(代码报红,注释了)
package com.hhh.config;
import com.hhh.filter.MyFilter;
import com.hhh.servlet.MyServlet;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import java.util.Set;
import javax.servlet.*;
import java.util.EnumSet;
import java.util.Set;
//ServletRegistration
public class WebServletContainerInitializer implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> set, ServletContext servletContext) throws ServletException {
System.out.println("this is run");
//注册servlet
// ServletRegistration.Dynamic dynamic= servletContext.addServlet("my",MyServlet.class);
// dynamic.addMapping("/my");
//
//注册filter
// FilterRegistration.Dynamic myFilter= servletContext.addFilter("MyFilter", MyFilter.class);
// myFilter.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST),true,"my");
}
}
四.无xml配置springmvc的原理
spring提供了一个org.springframework.web.SpringServletContainerInitializzer,也是利用了spi机制。
1.@HandlesTypes(WebApplicationInitializer.class)这个注解的作用
导入项目中的WebApplicationInitializer的实现类,放到SpringServletContainerInitializer类中的InStartip方法的参数1中,参数1是一个set集合。(参数2可用来注册Servlet)
2.SpringServletContainerInitializer的onStartup方法
//onStartup方法原理
//webAppInitializerClasses:这是class文件
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) throws ServletException {
//这个集合里头要放对象
List<WebApplicationInitializer> initializers = new LinkedList();
Iterator var4;
if (webAppInitializerClasses != null) {
var4 = webAppInitializerClasses.iterator();
while(var4.hasNext()) {
Class<?> waiClass = (Class)var4.next();
//判断class文件不是抽象类不是接口
if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) && WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
try {
//创建class的实例并放入集合 initializers.add((WebApplicationInitializer)waiClass.newInstance());
} catch (Throwable var7) {
throw new ServletException("Failed to instantiate WebApplicationInitializer class", var7);
}
}
}
}
if (initializers.isEmpty()) {
servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
} else {
AnnotationAwareOrderComparator.sort(initializers);
servletContext.log("Spring WebApplicationInitializers detected on classpath: " + initializers);
var4 = initializers.iterator();
执行实例的onStartip方法
while(var4.hasNext()) {
WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
initializer.onStartup(servletContext);
}
}
}
先判断set集合中的实现类是否都可以,然后这个接口会循环实现类的onStartup方法
3.在包config中新建一个配置类为AppIniConfig.java,继承某抽象类,实现各类方法
package com.hhh.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class AppInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
//读取spring的配置类——对应ApplicationContext
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
@Override
//指定springmvc的配置类——springmvc.xml
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
//指定前端控制器的拦截路径
protected String[] getServletMappings() {
//拦截所有路径
return new String[]{"/"};
}
}
4.去使用这个配置类,在config包中新建一个springmvc的配置类为SpringMvcConfig.java,而后新建controller包,在该类指定扫描路径
package com.hhh.config;
//springvc的配置类
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration //注解——这个类为表示为配置类
//指定扫描路径
@ComponentScan("com.hhh.controller")
public class SpringMvcConfig {
}
5.在controller包内新建一个类用来测试HelloController.java
package com.hhh.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
//映射路径
@RequestMapping("/hello")
public class HelloController {
@RequestMapping("/test1")
@ResponseBody
public String test1(){
return "test1";
//这个字符串会返回到前端
}
}
6.启动tomcat,运行程序查看效果
7.在webapp下放一个静态资源
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>First</title>
</head>
<body>
<h1>First</h1>
</body>
</html>
8.在SpringMvcConfig.java配置类中去处理静态资源
1.加注解:@EnableWebMvc
2.实现addResourceHandlers方法
package com.hhh.config;
//springvc的配置类
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.*;
import java.util.List;
@Configuration //注解——这个类为表示为配置类
//指定扫描路径
@ComponentScan("com.hhh.controller")
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry formatterRegistry) {
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> list) {
}
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> list) {
}
@Override
public Validator getValidator() {
return null;
}
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer contentNegotiationConfigurer) {
}
@Override
public void configureAsyncSupport(AsyncSupportConfigurer asyncSupportConfigurer) {
}
@Override
public void configurePathMatch(PathMatchConfigurer pathMatchConfigurer) {
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> list) {
}
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> list) {
}
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> list) {
}
@Override
public void addInterceptors(InterceptorRegistry interceptorRegistry) {
}
@Override
public MessageCodesResolver getMessageCodesResolver() {
return null;
}
@Override
public void addViewControllers(ViewControllerRegistry viewControllerRegistry) {
}
@Override
public void configureViewResolvers(ViewResolverRegistry viewResolverRegistry) {
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {
//静态资源处理方式的添加
resourceHandlerRegistry.addResourceHandler("/html/*").addResourceLocations("/");
}
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer defaultServletHandlerConfigurer) {
}
@Override
public void addCorsMappings(CorsRegistry corsRegistry) {
}
}
9.启动tomcat,运行程序,查看效果
五.无xmlWeb工程整合MyBatis——整合的本质还是在spring中配置MyBatis,包括以下步骤
1.新建domain,新建Manager类,其中的属性要依据数据表manager1中的字段一一对应
package com.hhh.domain;
public class Manager {
private String id;
private String name;
//无参的构造方法
public Manager(){
}
public Manager(String id, String name) {
this.id = id;
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Manager{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
2.新建dao包,新建接口ManagerDao.java
package com.hhh.dao;
import com.hhh.domain.Manager;
import java.util.List;
public interface ManagerDao {
public List<Manager> findAll();
public void insert(Manager manager);
public void delete(String id);
}
3.在四步骤中已经配置完springmvc ,接下来配置spring。在config包下新建一个类配置spring:SpringConig.java
package com.hhh.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import javax.sql.DataSource;
@Configuration //表示此类为配置类
@ComponentScan(basePackages ="com.hhh",
excludeFilters =@ComponentScan.Filter(type = FilterType.ANNOTATION,value = Controller.class))
//扫描除了controller之外的注解,basePackages指定基本的扫描路径, excludeFilters指定不扫描的路径,里面type为基于注解去排除
//3.配置MapperFactoryBean或者配置自动扫描dao层接口
@MapperScan("com.hhh.dao")
public class SpringConfig {
//记得去AppInitConfig类中添加需要读取的spring配置类
//配置bean
//1.配置连接池dataSource
@Bean
public DataSource dataSource(){
//创建DataSource,在pom文件导入数据库连接池的包
DruidDataSource dataSource=new DruidDataSource();
//ssmframe为数据库的数据库名
dataSource.setUrl("jdbc:mysql://localhost:3306/ssmframe");
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUsername("root");
dataSource.setPassword("hyt123456");
return dataSource;
}
//2.配置sqlSessionFactory
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(){
SqlSessionFactoryBean sqlSessionFactoryBean=new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
return sqlSessionFactoryBean;
}
//
}
这里有一个注意点,需要在AppInitConfig类中添加需要读取的spring配置类
4.在resource目录下新建一层和dao层一样的文件夹,在dao目录下新建一个ManagerDao.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hhh.dao.ManagerDao">
<select id="findAll" resultType="com.hhh.domain.Manager">
SELECT * FROM manager1
</select>
<!--这里的manager1为ssmframe数据库中的其中一个表-->
</mapper>
5.新建一个service,在service新建一个ManagerService去调用ManagerDao,这里节省步骤,直接在已有的HelloController类中去调用ManagerDAO
package com.hhh.controller;
import com.hhh.dao.ManagerDao;
import com.hhh.domain.Manager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
//映射路径
@RequestMapping("/hello")
public class HelloController {
@Autowired
private ManagerDao managerDao;
//这是idea的编译提示,不是编译报错,所以不影响代码运行的。这个bean只有在代码跑起来的时候才会被spring生成,未运行的时候是没有的。
@RequestMapping("/test1")
@ResponseBody
/*public String test1(){
return "test1";
//这个字符串会返回到前端
}*/
public List<Manager>test1(){
return managerDao.findAll();
}
}
6.注意,记得添加相关依赖
7.启动tomcat,在浏览器中查看效果
8.idea完整页面展示