通过拆分 Handler 通信管道处理器,引入 Shiro + JWT 到 AuthorizationHandler 中处理鉴权操作。
设计 一次网络请求经过 Netty 处理可以分为三段;消息接收、请求鉴权、消息处理。这样就由原来我们只是在接收消息后直接把消息协议转换后请求到 RPC 服务,转换为三层 Handler 来处理简单的消息接收、请求鉴权以及 RPC 泛化调用处理。
实现 Authorization 部分:
提供出进行 Shiro + JWT 进行鉴权的接口。
Mapping 部分:
在 HttpStatement 中新增布尔类型的 auth 属性,用于标记每个HTTP请求是否需要鉴权。例如GET请求并不一定需要鉴权,可以以游客的身份访问;用户账户信息则需要鉴权后才能访问。
将 IGenericReference 接口返回类型由 Object 具体为 SessionResult,方便后续直接使用包装的结果,而不用强转类型。
DataSource部分:
Session部分:
在 Configuration 中新增 AuthService 鉴权服务以及使用该服务的鉴权方法,便于后续在 Handler 中鉴权,另外新增注册 RPC 配置的方法,注入对应的 RPC 配置,便于后续构建 Dubbo 服务,并获取泛化调用服务。
Socket部分:
GatewayServerHandler 前置解析
这是请求鉴权的前置处理器,这里先简单处理,获取 HTTP 请求中的 URI ,用 URI 获取服务启动时注册的 HttpStatement 对象。
将 HttpStatement 对象保存至 channel#attr,则这条通信链路上的其他处理器都可以获取并使用该对象。
ctx.fireChannelRead(request); // 将request请求传递给下一个 handler
另外使用 request.retain(); // 增加request的引用计数,这是为了确保在后续处理中request不会被意外释放
而原来在该处理器中的一些会话操作,都后移了,这是为了先鉴权,等鉴权通过后再继续执行会话操作,避免提前开启会话造成资源浪费。
AuthorizationHandler 接口鉴权
获取上一个处理器传递的 HttpStatement 对象中的 auth 属性,属性值为 false ,则无需鉴权,直接放行交给下一个处理器。如果需要鉴权,则调用 Confguration#AuthService 对 HTTP 请求进行鉴权,鉴权成功则放行。
ProtocolDataHandler 泛化调用处理
该处理器就是之前章节的GatewayServerHandler,只是在本章更新为ProtocoiDatalandler,用于泛化调用服务。
新增 AgreementConstants ,枚举 HTTP 返回状态码
新增 GatewayResult ,用于封装网关的返回结果
配置定义 HttpStatement 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 74 75 76 77 78 package cn.ray.gateway.mapping;public class HttpStatement { private String application; private String interfaceName; private String methodName; private String uri; private HttpRequestType httpRequestType; private String parameterType; private boolean auth; public HttpStatement (String application, String interfaceName, String methodName, String uri, HttpRequestType httpRequestType, String parameterType, boolean auth) { this .application = application; this .interfaceName = interfaceName; this .methodName = methodName; this .uri = uri; this .httpRequestType = httpRequestType; this .parameterType = parameterType; this .auth = auth; } public String getApplication () { return application; } public String getInterfaceName () { return interfaceName; } public String getMethodName () { return methodName; } public String getUri () { return uri; } public HttpRequestType getHttpRequestType () { return httpRequestType; } public String getParameterType () { return parameterType; } public boolean isAuth () { return auth; } }
Configuration 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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 package cn.ray.gateway.session;import cn.ray.gateway.authorization.IAuth;import cn.ray.gateway.authorization.auth.AuthService;import cn.ray.gateway.bind.MapperRegistry;import cn.ray.gateway.bind.IGenericReference;import cn.ray.gateway.datasource.Connection;import cn.ray.gateway.executor.Executor;import cn.ray.gateway.executor.SimpleExecutor;import cn.ray.gateway.mapping.HttpStatement;import org.apache.dubbo.config.ApplicationConfig;import org.apache.dubbo.config.ReferenceConfig;import org.apache.dubbo.config.RegistryConfig;import org.apache.dubbo.rpc.service.GenericService;import java.util.HashMap;import java.util.Map;public class Configuration { private final MapperRegistry mapperRegistry = new MapperRegistry (this ); private final IAuth auth = new AuthService (); private final Map<String, HttpStatement> httpStatementMap = new HashMap <>(); private final Map<String, ApplicationConfig> applicationConfigMap = new HashMap <>(); private final Map<String, RegistryConfig> registryConfigMap = new HashMap <>(); private final Map<String, ReferenceConfig<GenericService>> referenceConfigMap = new HashMap <>(); public Configuration () { } public synchronized void registerConfig (String applicationName, String address, String interfaceName, String version) { if (applicationConfigMap.get(applicationName) == null ) { ApplicationConfig application = new ApplicationConfig (); application.setName(applicationName); application.setQosEnable(false ); applicationConfigMap.put(applicationName, application); } if (registryConfigMap.get(applicationName) == null ) { RegistryConfig registry = new RegistryConfig (); registry.setAddress(address); registry.setRegister(false ); registryConfigMap.put(applicationName, registry); } if (referenceConfigMap.get(interfaceName) == null ) { ReferenceConfig<GenericService> reference = new ReferenceConfig <>(); reference.setInterface(interfaceName); reference.setVersion(version); reference.setGeneric("true" ); referenceConfigMap.put(interfaceName, reference); } } public ApplicationConfig getApplicationConfig (String applicationName) { return applicationConfigMap.get(applicationName); } public RegistryConfig getRegistryConfig (String applicationName) { return registryConfigMap.get(applicationName); } public ReferenceConfig<GenericService> getReferenceConfig (String interfaceName) { return referenceConfigMap.get(interfaceName); } public void addMapper (HttpStatement httpStatement) { mapperRegistry.addMapper(httpStatement); } public IGenericReference getMapper (String uri, GatewaySession gatewaySession) { return mapperRegistry.getMapper(uri, gatewaySession); } public void addHttpStatement (HttpStatement httpStatement) { httpStatementMap.put(httpStatement.getUri(), httpStatement); } public HttpStatement getHttpStatement (String uri) { return httpStatementMap.get(uri); } public Executor newExecutor (Connection connection) { return new SimpleExecutor (this , connection); } public boolean authValidate (String uId, String token) { return auth.validate(uId, token); } }
GatewayServerHandler 前置解析 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 package cn.ray.gateway.socket.handlers;import cn.ray.gateway.bind.IGenericReference;import cn.ray.gateway.mapping.HttpStatement;import cn.ray.gateway.session.Configuration;import cn.ray.gateway.session.GatewaySession;import cn.ray.gateway.session.defaults.DefaultGatewaySessionFactory;import cn.ray.gateway.socket.BaseHandler;import cn.ray.gateway.socket.agreement.AgreementConstants;import cn.ray.gateway.socket.agreement.GatewayResult;import cn.ray.gateway.socket.agreement.RequestParser;import cn.ray.gateway.socket.agreement.ResponseParser;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.serializer.SerializerFeature;import io.netty.channel.Channel;import io.netty.channel.ChannelHandlerContext;import io.netty.handler.codec.http.*;import io.netty.util.AttributeKey;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.Map;public class GatewayServerHandler extends BaseHandler <FullHttpRequest> { private final Logger logger = LoggerFactory.getLogger(GatewayServerHandler.class); private final Configuration configuration; public GatewayServerHandler (Configuration configuration) { this .configuration = configuration; } @Override protected void session (ChannelHandlerContext ctx, Channel channel, FullHttpRequest request) { logger.info("网关接收请求【 全局 】 ===> uri: {} , method: {}" , request.uri(), request.method()); try { RequestParser requestParser = new RequestParser (request); String uri = requestParser.getUri(); HttpStatement httpStatement = configuration.getHttpStatement(uri); channel.attr(AgreementConstants.HTTP_STATEMENT).set(httpStatement); request.retain(); ctx.fireChannelRead(request); } catch (Exception e) { DefaultFullHttpResponse response = new ResponseParser ().parse(GatewayResult.buildError(AgreementConstants.ResponseCode._500.getCode(), "网关协议调用失败!" + e.getMessage())); channel.writeAndFlush(response); } } }
AuthorizationHandler 接口鉴权 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 package cn.ray.gateway.socket.handlers;import cn.ray.gateway.mapping.HttpStatement;import cn.ray.gateway.session.Configuration;import cn.ray.gateway.socket.BaseHandler;import cn.ray.gateway.socket.agreement.AgreementConstants;import cn.ray.gateway.socket.agreement.GatewayResult;import cn.ray.gateway.socket.agreement.ResponseParser;import io.netty.channel.Channel;import io.netty.channel.ChannelHandlerContext;import io.netty.handler.codec.http.DefaultFullHttpResponse;import io.netty.handler.codec.http.FullHttpRequest;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class AuthorizationHandler extends BaseHandler <FullHttpRequest> { private final Logger logger = LoggerFactory.getLogger(AuthorizationHandler.class); private final Configuration configuration; public AuthorizationHandler (Configuration configuration) { this .configuration = configuration; } @Override protected void session (ChannelHandlerContext ctx, Channel channel, FullHttpRequest request) { logger.info("网关接收请求【 鉴权 】 ===> uri: {} , method: {}" , request.uri(), request.method()); HttpStatement httpStatement = channel.attr(AgreementConstants.HTTP_STATEMENT).get(); try { if (httpStatement.isAuth()) { try { String uId = request.headers().get("uId" ); String token = request.headers().get("token" ); if (null == token || "" .equals(token)) { DefaultFullHttpResponse response = ResponseParser.parse(GatewayResult.buildError(AgreementConstants.ResponseCode._400.getCode(), "对不起,你的 token 不合法!" )); channel.writeAndFlush(response); } boolean status = configuration.authValidate(uId, token); if (status) { request.retain(); ctx.fireChannelRead(request); } else { DefaultFullHttpResponse response = ResponseParser.parse(GatewayResult.buildError(AgreementConstants.ResponseCode._403.getCode(), "对不起,你无权访问此接口!" )); channel.writeAndFlush(response); } } catch (Exception e) { DefaultFullHttpResponse response = ResponseParser.parse(GatewayResult.buildError(AgreementConstants.ResponseCode._403.getCode(), "对不起,你的鉴权不合法!" )); channel.writeAndFlush(response); } } else { request.retain(); ctx.fireChannelRead(request); } } catch (Exception e) { DefaultFullHttpResponse response = ResponseParser.parse(GatewayResult.buildError(AgreementConstants.ResponseCode._500.getCode(), "网关协议调用失败!" + e.getMessage())); channel.writeAndFlush(response); } } }
GatewayAuthorizingRealm 自定义 Shiro 验证领域 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 package cn.ray.gateway.authorization;import io.jsonwebtoken.Claims;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;public class GatewayAuthorizingRealm extends AuthorizingRealm { @Override public Class<?> getAuthenticationTokenClass() { return GatewayAuthorizingToken.class; } @Override protected AuthorizationInfo doGetAuthorizationInfo (PrincipalCollection principalCollection) { return null ; } @Override protected AuthenticationInfo doGetAuthenticationInfo (AuthenticationToken authenticationToken) throws AuthenticationException { try { Claims claims = JwtUtil.decode(((GatewayAuthorizingToken) authenticationToken).getJwt()); if (!authenticationToken.getPrincipal().equals(claims.getSubject())) throw new AuthenticationException ("无效令牌" ); } catch (Exception e) { throw new AuthenticationException ("无效令牌" ); } return new SimpleAuthenticationInfo (authenticationToken.getPrincipal(), authenticationToken.getCredentials(), this .getName()); } }
这里的鉴权逻辑是验证 token 签发人是否一致,即生成 token 时指定的 Subject (签发人,类似userld.userName)与 POST 请求时 Headers 中携带的 uId 是否一致,确保获取 token 的用户和使用 token 的用户是同一个,鉴权才通过。
JwtUtil 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 package cn.ray.gateway.authorization;import io.jsonwebtoken.Claims;import io.jsonwebtoken.JwtBuilder;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgorithm;import java.util.Date;import java.util.HashMap;import java.util.Map;public class JwtUtil { private static final String signingKey = "B*B^5Fe" ; public static String encode (String issuer, long ttlMillis, Map<String, Object> claims) { if (null == claims) { claims = new HashMap <>(); } long currentMillis = System.currentTimeMillis(); Date currentTime = new Date (currentMillis); JwtBuilder jwtBuilder = Jwts.builder() .setClaims(claims) .setIssuedAt(currentTime) .setSubject(issuer) .signWith(SignatureAlgorithm.HS256, signingKey); if (ttlMillis>=0 ) { long expMillis = currentMillis + ttlMillis; Date expTime = new Date (expMillis); jwtBuilder.setExpiration(expTime); } return jwtBuilder.compact(); } public static Claims decode (String token) { return Jwts.parser() .setSigningKey(signingKey) .parseClaimsJws(token) .getBody(); } }
ProtocolDataHandler 泛化调用处理 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 package cn.ray.gateway.socket.handlers;import cn.ray.gateway.bind.IGenericReference;import cn.ray.gateway.executor.result.SessionResult;import cn.ray.gateway.session.GatewaySession;import cn.ray.gateway.session.defaults.DefaultGatewaySessionFactory;import cn.ray.gateway.socket.BaseHandler;import cn.ray.gateway.socket.agreement.AgreementConstants;import cn.ray.gateway.socket.agreement.GatewayResult;import cn.ray.gateway.socket.agreement.RequestParser;import cn.ray.gateway.socket.agreement.ResponseParser;import io.netty.channel.Channel;import io.netty.channel.ChannelHandlerContext;import io.netty.handler.codec.http.DefaultFullHttpResponse;import io.netty.handler.codec.http.FullHttpRequest;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.Map;public class ProtocolDataHandler extends BaseHandler <FullHttpRequest> { private final Logger logger = LoggerFactory.getLogger(ProtocolDataHandler.class); private final DefaultGatewaySessionFactory gatewaySessionFactory; public ProtocolDataHandler (DefaultGatewaySessionFactory gatewaySessionFactory) { this .gatewaySessionFactory = gatewaySessionFactory; } @Override protected void session (ChannelHandlerContext ctx, Channel channel, FullHttpRequest request) { logger.info("网关接收请求【 消息 】 uri:{} method:{}" , request.uri(), request.method()); try { RequestParser requestParser = new RequestParser (request); String uri = requestParser.getUri(); if (null == uri) return ; Map<String, Object> args = requestParser.parse(); GatewaySession gatewaySession = gatewaySessionFactory.openSession(uri); IGenericReference reference = gatewaySession.getMapper(); SessionResult result = reference.$invoke(args); DefaultFullHttpResponse response = ResponseParser.parse("0000" .equals(result.getCode()) ? GatewayResult.buildSuccess(result.getData()) : GatewayResult.buildError(AgreementConstants.ResponseCode._404.getCode(), "网关协议调用失败!" )); channel.writeAndFlush(response); } catch (Exception e) { DefaultFullHttpResponse response = ResponseParser.parse(GatewayResult.buildError(AgreementConstants.ResponseCode._502.getCode(), "网关协议调用失败!" + e.getMessage())); channel.writeAndFlush(response); } } }
AgreementConstants 协议参数 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 package cn.ray.gateway.socket.agreement;import cn.ray.gateway.mapping.HttpStatement;import io.netty.util.AttributeKey;public class AgreementConstants { public static final AttributeKey<HttpStatement> HTTP_STATEMENT = AttributeKey.valueOf("HttpStatement" ); public enum ResponseCode { _200("200" ,"访问成功" ), _400("400" ,"接收数据的数据类型不匹配" ), _403("403" ,"服务器拒绝请求" ), _404("404" ,"服务器找不到请求的网页,输入链接有误" ), _500("500" ,"服务器遇到错误,无法完成请求" ), _502("502" ,"服务器作为网关或代理,从上游服务器收到无效响应" ); private String code; private String info; ResponseCode(String code, String info) { this .code = code; this .info = info; } public String getCode () { return code; } public String getInfo () { return info; } } }
GatewayResult 网关结果封装 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 package cn.ray.gateway.socket.agreement;public class GatewayResult { private String code; private String message; private Object data; protected GatewayResult (String code, String info, Object data) { this .code = code; this .message = info; this .data = data; } public static GatewayResult buildSuccess (Object data) { return new GatewayResult (AgreementConstants.ResponseCode._200.getCode(), AgreementConstants.ResponseCode._200.getInfo(), data); } public static GatewayResult buildError (String code, String info) { return new GatewayResult (code, info, null ); } public String getCode () { return code; } public String getMessage () { return message; } public Object getData () { return data; } }
测试 RPC 服务 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 package cn.ray.gateway.interfaces;import cn.ray.gateway.rpc.IActivityBooth;import cn.ray.gateway.rpc.dto.XReq;import com.alibaba.fastjson.JSON;import org.apache.dubbo.config.annotation.Service;@Service(version = "1.0.0") public class ActivityBooth implements IActivityBooth { @Override public String sayHi (String str) { return "hi " + str + " by api-gateway-test" ; } @Override public String insert (XReq req) { return "hi " + JSON.toJSONString(req) + " by api-gateway-test" ; } @Override public String test (String str, XReq req) { return "hi " + str + JSON.toJSONString(req) + " by api-gateway-test" ; } }
启动网关 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 package cn.ray.gateway.test;import cn.ray.gateway.mapping.HttpRequestType;import cn.ray.gateway.mapping.HttpStatement;import cn.ray.gateway.session.Configuration;import cn.ray.gateway.session.defaults.DefaultGatewaySessionFactory;import cn.ray.gateway.socket.GatewaySocketServer;import io.netty.channel.Channel;import org.junit.Test;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.concurrent.ExecutionException;import java.util.concurrent.Executors;import java.util.concurrent.Future;public class ApiTest { private final Logger logger = LoggerFactory.getLogger(ApiTest.class); @Test public void test_GenericReference () throws InterruptedException, ExecutionException { Configuration configuration = new Configuration (); configuration.registerConfig("api-gateway-test" ,"zookeeper://127.0.0.1:2181" ,"cn.ray.gateway.rpc.IActivityBooth" , "1.0.0" ); HttpStatement httpStatement01 = new HttpStatement ( "api-gateway-test" , "cn.ray.gateway.rpc.IActivityBooth" , "sayHi" , "/wg/activity/sayHi" , HttpRequestType.GET, "java.lang.String" , false ); HttpStatement httpStatement02 = new HttpStatement ( "api-gateway-test" , "cn.ray.gateway.rpc.IActivityBooth" , "insert" , "/wg/activity/insert" , HttpRequestType.POST, "cn.ray.gateway.rpc.dto.XReq" , true ); configuration.addMapper(httpStatement01); configuration.addMapper(httpStatement02); DefaultGatewaySessionFactory gatewaySessionFactory = new DefaultGatewaySessionFactory (configuration); GatewaySocketServer server = new GatewaySocketServer (configuration, gatewaySessionFactory); Future<Channel> future = Executors.newFixedThreadPool(2 ).submit(server); Channel channel = future.get(); if (null == channel) throw new RuntimeException ("netty server start error channel is null" ); while (!channel.isActive()) { logger.info("netty server gateway start Ing ..." ); Thread.sleep(500 ); } logger.info("netty server gateway start Done! {}" , channel.localAddress()); Thread.sleep(Long.MAX_VALUE); } }
测试结果 GET 不鉴权
POST 鉴权 JWT 生成 token 时指定的签发人与当前 Headers 中的 uId 不一致,也即 token 与 uId 不对应。
JWT 生成 token 时指定的签发人与当前 Headers 中的 uId 一致。
总结
总算理清了 Cglib 代理流程:
intercept
方法是CGLIB库中的拦截器接口 MethodInterceptor
的方法,在代码中被重写以实现自定义的拦截逻辑。该方法会拦截代理对象的所有方法调用,包括代理对象的父类方法和接口方法。
intercept 方法是拦截器的核心方法,用于拦截目标方法的调用并进行处理。它接收以下参数:
o:代理对象。
method:目标方法的反射对象。
objects:目标方法的参数数组。
methodProxy:用于调用目标方法的方法代理对象。
MethodProxy
是CGLIB库提供的一个方法代理对象,用于调用目标方法。
在CGLIB代理中,当拦截器的 intercept
方法被调用时,可以使用 MethodProxy
对象来调用目标方法,而不是直接通过反射调用目标方法。这样做的好处是可以绕过反射的性能开销,提高方法调用的效率。
具体来说,MethodProxy
的 invokeSuper(Object obj, Object[] args)
方法可以用来调用目标方法。它接受两个参数:
obj
:目标方法所属的对象,即代理对象。
args
:目标方法的参数数组。
通过调用 invokeSuper
方法,可以在拦截器中将方法调用传递给目标方法。这样就可以在拦截器中实现自定义的逻辑,并在适当的时机调用目标方法。
通过调用 invokeSuper
方法,可以在拦截器中将方法调用传递给目标方法。这样就可以在拦截器中实现自定义的逻辑,并在适当的时机调用目标方法。
总结来说,MethodProxy
提供了一种高效的方式来调用目标方法,避免了反射带来的性能开销,并且可以与拦截器协同工作,实现代理对象方法的拦截和处理。
在这段代码中,intercept
方法被用作代理对象的拦截器,它会拦截目标方法的调用并进行处理。具体来说,它拦截的是代理对象中任何被调用的方法 ,不限于某一个具体的方法。
当代理对象的方法被调用时,CGLIB库会将该调用传递给 intercept
方法,在该方法内部可以实现自定义的拦截逻辑。在代码中,intercept
方法使用了 MapperMethod
对象来表示要执行的映射方法,并调用了该方法的 execute
方法来执行映射逻辑。
总之,intercept
方法在这里作为一个通用的拦截器,用于处理代理对象的所有方法调用,并在其中实现特定的逻辑。
如果你想要在 intercept
方法中只拦截指定的方法,可以在方法内部添加条件判断逻辑。以下是一个示例,演示如何只拦截指定方法的调用:
1 2 3 4 5 6 7 8 9 10 @Override public Object intercept (Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { if (method.getName().equals("methodName" )) { } return methodProxy.invokeSuper(o, objects); }
在上述示例中,我们使用了 method.getName().equals("methodName")
条件判断来判断目标方法的名称是否为我们希望拦截的方法名。如果是,可以在条件判断的分支中添加自定义的拦截逻辑。对于其他方法,我们直接调用 methodProxy.invokeSuper(o, objects)
来调用目标方法,实现不拦截的效果。
网关启动 Netty 服务
全流程
权限认证组件 Shiro + JWT