javase
动态加载字节码
使用defineClass 加载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| import java.lang.reflect.Method; import java.util.Base64; public class HelloDefineClass { public static void main(String[] args) throws Exception { Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); defineClass.setAccessible(true); byte[] code = Base64.getDecoder().decode("yv66vgAAADQAGwoABgANCQAOAA8IABAKABEAEgcAEwcAFAEA Bjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApTb3VyY2VGaWxlAQAKSGVs bG8uamF2YQwABwAIBwAVDAAWABcBAAtIZWxsbyBXb3JsZAcAGAwAGQAaAQAFSGVsbG8BABBqYXZh L2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3Ry ZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5n OylWACEABQAGAAAAAAABAAEABwAIAAEACQAAAC0AAgABAAAADSq3AAGyAAISA7YABLEAAAABAAoA AAAOAAMAAAACAAQABAAMAAUAAQALAAAAAgAM"); Class hello = (Class)defineClass.invoke(ClassLoader.getSystemClassLoader(), "Hello", code, 0, code.length); hello.newInstance(); } }
|
使用URLClassLoader加载
1 2 3 4 5 6 7 8 9 10 11 12
| import java.net.URL; import java.net.URLClassLoader; public class HelloClassLoader { public static void main( String[] args ) throws Exception { URL[] urls = {new URL("http://localhost:8000/")}; URLClassLoader loader = URLClassLoader.newInstance(urls); Class c = loader.loadClass("Hello"); c.newInstance(); } }
|
动态代理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;
// 1. 定义接口 interface UserService { void addUser(String name); void deleteUser(String name); }
// 2. 实现接口的实际类 class UserServiceImpl implements UserService { @Override public void addUser(String name) { System.out.println("添加用户: " + name); } @Override public void deleteUser(String name) { System.out.println("删除用户: " + name); } }
// 3. 实现调用处理器(InvocationHandler) class LoggingHandler implements InvocationHandler { private Object target; // 被代理的对象 public LoggingHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在方法调用前添加日志 System.out.println("开始执行方法: " + method.getName()); // 调用实际对象的方法 Object result = method.invoke(target, args); // 在方法调用后添加日志 System.out.println("方法执行完成: " + method.getName()); return result; } }
// 4. 测试类 public class DynamicProxyDemo { public static void main(String[] args) { // 创建实际对象 UserService realService = new UserServiceImpl(); // 创建调用处理器,传入实际对象 InvocationHandler handler = new LoggingHandler(realService); // 创建动态代理对象 UserService proxyService = (UserService) Proxy.newProxyInstance( UserService.class.getClassLoader(), // 类加载器 new Class[]{UserService.class}, // 代理的接口 handler // 调用处理器 ); // 通过代理对象调用方法 System.out.println("=== 通过代理调用方法 ==="); proxyService.addUser("张三"); System.out.println(); proxyService.deleteUser("李四"); System.out.println("\n=== 直接调用方法 ==="); // 对比直接调用实际对象的方法 realService.addUser("王五"); } }
|
springboot
cookie与session
1 2 3 4 5 6 7 8 9 10
| Cookie cookie = new Cookie(name, value); cookie.setMaxAge(maxAge); cookie.setPath("/"); // 添加Cookie到响应 response.addCookie(cookie); HttpSession session = request.getSession(true); session.setAttribute(key, value);
|
java filter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| @WebFilter("/*") public class LoggingFilter implements Filter { private FilterConfig filterConfig; @Override public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; System.out.println("LoggingFilter初始化完成"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String requestURI = httpRequest.getRequestURI(); String remoteAddr = request.getRemoteAddr(); Date timestamp = new Date(); // 记录请求开始时间 long startTime = System.currentTimeMillis(); // 输出请求信息到控制台 System.out.println("[" + timestamp + "] 请求开始: " + requestURI + " from " + remoteAddr); // 执行后续过滤器或Servlet chain.doFilter(request, response); // 计算请求处理时间 long processingTime = System.currentTimeMillis() - startTime; // 输出请求完成信息 System.out.println("[" + new Date() + "] 请求完成: " + requestURI + " 处理时间: " + processingTime + "ms"); } @Override public void destroy() { System.out.println("LoggingFilter销毁"); } }
|
jwt
1 2 3 4 5 6
| Jwts.builder() .setSubject(username) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() + REFRESH_EXPIRATION_TIME)) .signWith(SECRET_KEY) .compact();
|
Interceptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| package com.example.demo.interceptor;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView;
@Component public class DemoInterceptor implements HandlerInterceptor {
private static final Logger logger = LoggerFactory.getLogger(DemoInterceptor.class);
// 在Controller方法执行之前调用 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { long startTime = System.currentTimeMillis(); request.setAttribute("startTime", startTime);
String requestURI = request.getRequestURI(); String clientIP = request.getRemoteAddr(); logger.info(">>> preHandle: Request URL=[{}], Client IP=[{}]", requestURI, clientIP);
// 认证检查示例(简单版) String token = request.getHeader("Authorization"); if (token == null || !token.startsWith("Bearer ")) { logger.warn("Access denied: Missing or invalid token"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); return false; // 中断请求,不再调用Controller } // 可以在这里解析Token并将用户信息放入request attribute,供Controller使用 // request.setAttribute("userInfo", parsedUserInfo);
return true; // 继续执行,调用下一个拦截器或Controller }
// 在Controller方法执行之后,视图渲染之前调用 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { logger.info(">>> postHandle: Request handled successfully."); // 可以对ModelAndView进行修改 }
// 在整个请求完成之后调用(视图渲染完毕) @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { long startTime = (Long) request.getAttribute("startTime"); long endTime = System.currentTimeMillis(); long executeTime = endTime - startTime;
String requestURI = request.getRequestURI(); logger.info(">>> afterCompletion: Request URL=[{}], Time Taken=[{}ms]", requestURI, executeTime);
if (ex != null) { logger.error("Request processing failed with exception: ", ex); } } }
|
注册拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com.example.demo.config;
import com.example.demo.interceptor.DemoInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration public class WebConfig implements WebMvcConfigurer {
@Autowired private DemoInterceptor demoInterceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(demoInterceptor) .addPathPatterns("/api/**") // 拦截所有以 /api 开头的路径 .excludePathPatterns("/api/public/**", "/api/auth/login"); // 排除特定的公开路径 } }
|
拦截器与过滤器执行顺序

aop




切入点表达式的几种写法


常用注解
| 注解类别 |
主要注解 |
用途 |
| 启动类 |
@SpringBootApplication |
主启动注解 |
| 配置类 |
@Configuration, @Bean |
配置Bean定义 |
| 组件 |
@Component, @Service, @Repository, @Controller |
组件声明 |
| 依赖注入 |
@Autowired, @Qualifier, @Primary |
依赖管理 |
| Web |
@RestController, @GetMapping, @PostMapping |
Web控制器 |
| 事务 |
@Transactional |
事务管理 |
| 测试 |
@SpringBootTest, @MockBean |
测试支持 |
| 条件 |
@ConditionalOnProperty, @Profile |
条件化配置 |
| AOP |
@Aspect, @Around |
切面编程 |
| 调度 |
@Scheduled |
定时任务 |
1
| @ModelAttribute 将 HTTP 请求参数(表单数据、查询参数)绑定到一个 Java 对象
|
springmvc
web.xml功能
第一步:编写 Filter 类 (CharacterEncodingFilter.java)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class CharacterEncodingFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 在请求到达Servlet之前执行:设置编码 request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8");
System.out.println("CharacterEncodingFilter: Setting UTF-8 encoding"); // 放行请求,继续执行后续的过滤器或最终的Servlet chain.doFilter(request, response); // 在响应发送给客户端之后执行(这里可以做一些日志记录等收尾工作) } // init 和 destroy 方法通常留空 }
|
第二步:在 web.xml 中配置 Filter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <!-- 1. 声明过滤器 --> <filter> <filter-name>encodingFilter</filter-name> <filter-class>com.example.CharacterEncodingFilter</filter-class> </filter>
<!-- 2. 映射过滤器到URL --> <filter-mapping> <filter-name>encodingFilter</filter-name> <!-- 对所有URL请求都进行过滤 --> <url-pattern>/*</url-pattern> <!-- 你也可以用另一种方式:指定对哪些Servlet的请求进行过滤 --> <!-- <servlet-name>LoginServlet</servlet-name> --> </filter-mapping>
|
效果:任何一个请求(/*)到达任何 Servlet 之前,都会先经过这个过滤器,从而保证了整个应用不会出现中文乱码问题。
3. 配置监听器 (Listener)
作用:监听 Web 应用生命周期中的事件,如:应用的启动与销毁、Session 的创建与失效等,并执行相应的初始化或清理代码。
举例:在应用启动时(服务器启动),初始化一个数据库连接池。
第一步:编写 Listener 类 (AppContextListener.java)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class AppContextListener implements ServletContextListener { // 应用启动时调用 @Override public void contextInitialized(ServletContextEvent sce) { System.out.println("Web Application is starting up..."); // 模拟初始化一个昂贵的资源,比如数据库连接池 // BasicDataSource dataSource = new BasicDataSource(); // dataSource.setUrl("jdbc:mysql://localhost:3306/mydb"); // ... // 将这个资源放入ServletContext中,供整个应用使用 // sce.getServletContext().setAttribute("DATABASE_POOL", dataSource); System.out.println("Database connection pool initialized."); } // 应用关闭时调用 @Override public void contextDestroyed(ServletContextEvent sce) { System.out.println("Web Application is shutting down..."); // 进行资源清理,如关闭数据库连接池 // BasicDataSource dataSource = (BasicDataSource) sce.getServletContext().getAttribute("DATABASE_POOL"); // if (dataSource != null) { // dataSource.close(); // } } }
|
第二步:在 web.xml 中配置 Listener
xml
1 2 3
| <listener> <listener-class>com.example.AppContextListener</listener-class> </listener>
|
效果:当 Tomcat 等服务器启动加载这个Web应用时,会自动调用 contextInitialized 方法;当服务器关闭或应用被卸载时,会自动调用 contextDestroyed 方法。
4. 配置应用初始化参数 (Context Parameters)
作用:定义一些全局的、整个Web应用都可以访问的配置参数,比如版本号、文件上传路径等。
举例:配置一个全局的文件上传保存路径。
在 web.xml 中配置:
1 2 3 4 5 6 7 8 9
| <context-param> <param-name>UPLOAD_DIRECTORY</param-name> <!-- 参数名 --> <param-value>/opt/app/uploads</param-value> <!-- 参数值 --> </context-param>
<context-param> <param-name>APP_VERSION</param-name> <param-value>1.0.0</param-value> </context-param>
|
在代码中获取参数:
java
1 2 3
| // 在任何Servlet或Filter中都可以获取 String uploadPath = getServletContext().getInitParameter("UPLOAD_DIRECTORY"); String appVersion = getServletContext().getInitParameter("APP_VERSION");
|
5. 配置欢迎页 (Welcome File)
作用:当用户访问一个目录路径(如 http://domain.com/)而非具体文件时,服务器会自动尝试寻找并返回欢迎页列表中的文件。
在 web.xml 中配置:
1 2 3 4 5 6
| <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>default.html</welcome-file> </welcome-file-list>
|
效果:访问 http://yourdomain.com/yourApp/ 时,服务器会按顺序在根目录下查找 index.html -> index.jsp -> index.htm -> default.html,找到第一个存在的文件并返回。
6. 配置错误页面 (Error Page)
作用:当发生特定HTTP错误(如404、500)或Java异常时,显示一个友好的自定义页面,而不是暴露服务器默认的错误信息。
举例:配置 404 和 500 错误的自定义页面。
在 web.xml 中配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <!-- 根据HTTP错误代码跳转 --> <error-page> <error-code>404</error-code> <location>/error-404.html</location> </error-page> <error-page> <error-code>500</error-code> <location>/error-500.html</location> </error-page>
<!-- 根据Java异常类型跳转 --> <error-page> <exception-type>java.lang.NullPointerException</exception-type> <location>/error-npe.html</location> </error-page>
|
springsecurity
