组件必知必会|那些年我们使用过的轮子—Filter和Proxy
前言
过滤器Filter是JavaWeb三大组件之一,它与Servlet很相似,过滤器是用来拦截请求的,而不是处理请求的。当用户请求某个Servlet时,会先执行部署在这个请求上的Filter,如果Filter“放行”,那么会继承执行用户请求的Servlet;如果Filter“不放行”,那么就不会执行用户请求的Servlet。可以这样理解,当用户请求某个Servlet时,Tomcat会去执行注册在这个请求上的Filter,然后是否“放行”由Filter来决定。可以理解为,Filter来决定是否调用Servlet!当执行完成Servlet的代码后,还会执行Filter后面的代码。
设计模式不是技术,也不是什么框架,只是前人的一个工作的总结,在实现某一个功能的时候,怎样来减少代码之间的耦合性,以及如何实现高内聚低耦合,设计模式说白了就是按照一定的步骤来完成相应的一个功能,这个就称为设计模式。代理Proxy是指给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗来讲,代理设计模式就是我们生活中常见的中介。主要用来解决的问题第一个:监控目录一个类里面的方法的执行,第二个:在类里面某一个方法执行的前后动态的植入代码。
本文将带大家详细介绍Filter以及Proxy的具体原理以及使用。
公众号:「浅羽的IT小屋」
1、什么是过滤器
「定义:」
2、过滤器的作用
「主要用途:」
3、过滤器的使用
「使用案例:」
public class HelloFilter implements Filter{
/**
* 在Filter实例被创建的时候 初始化方法的时候执行的 这个一般用于Filter的初始化
* filterConfig:获取的是Filter的配置信息以及初始化信息的 */
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init初始化执行了");
}
/**
* 过滤器拦截的方法
* request:当前的请求对象的封装
* response:当前的响应的封装
* chain:判断是否拦截的方法
* */
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("doFilter执行了....");
//执行了这个方法那么就表示允许通过 没有执行那么就不允许通过
chain.doFilter(request, response);
}
/**
* 过滤器在死了之后 执行的这个方法 */
@Override
public void destroy() {
System.out.println("destory执行了....");
}
}
<filter>
<filter-name>HelloFilter</filter-name>
<filter-class>com.qy.filter.HelloFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>HelloFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4、过滤器的生命周期
「生命周期:」
public HelloFilter() {
System.out.println("类的对象被创建了....");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init初始化执行了");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("doFilter执行了....");
// 执行了这个方法那么就表示允许通过 没有执行那么就不允许通过
//放行
// chain.doFilter(request, response);
}
@Override
public void destroy() {
System.out.println("destory执行了....");
}
在web.xml中给filter添加初始数据
<filter>
<filter-name>HelloFilter</filter-name>
<filter-class>com.qy.filter.HelloFilter</filter-class>
<init-param>
<param-name>userName</param-name>
<param-value>qianyu</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123</param-value>
</init-param>
</filter>
使用filterConfig来获取这个数据
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init初始化执行了");
//获取fileter的初始化数据
String userName=filterConfig.getInitParameter("userName");
String password=filterConfig.getInitParameter("password");
//获取的所有参数的名字
filterConfig.getInitParameterNames();
//获取的是application
filterConfig.getServletContext();
//获取的是Filter的名字
filterConfig.getFilterName();
System.out.println("获取到的数据是:"+userName+"----"+password);
}
过滤中器放行的方法是什么?
chain.doFilter(request, response);
5、代理设计模式
「解决的问题:」
什么是设计模式? 设计模式不是技术、也不是什么框架、设计模式只是前人的一个工作的总结、在实现某一个功能的时候 怎样来减少代码之间的耦合性、以及如何实现高内聚低耦合。设计模式说白了就是按照一定的步骤来完成相应的一个功能 这个就称为设计模式
代理的设计模式主要用来解决一个什么问题呢? 第一个:监控目录一个类里面方法的执行 第二个:在类里面某一个方法执行的前后 动态的植入代码
「静态代理:」
接口的玩法
「动态代理(JDK代理):」
动态代理的实现原理:实际上也是生成了接口的实现类对象、然后在接口的实现类对象里面传入了 被代理的对象、在方法执行的时候使用了被代理类的方法去执行、实际上就跟静态代理差不多 区别是静态代理自己写的代 理类、动态代理是自动生成的这个代理类
IUserDAO userDAO=(IUserDAO)Proxy.newProxyInstance(
UserDAO.class.getClassLoader(),
UserDAO.class.getInterfaces(),
new InvocationHandler() {
/**
* 第一个参数:代理对象
* 第二个参数:当前要执行方法的一个封装
* 第三个参数:执行方法要传递的这个参数 */
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("执行前添加的功能....");
Object result=method.invoke(new UserDAO(), args);
System.out.println("执行后添加的功能....");
return result;
}
});
userDAO.save();
「cglib代理:」
cglib的使用场景:就是一个类如果没有实现接口 而且我们想在这个类的方法里面动态植入代码 那么这种情况下就可以使用cglib代理
public class UserDAOProxy {
private UserDAO userDAO=null;
public UserDAOProxy(UserDAO userDAO) {
this.userDAO=userDAO;
}
/**
* 编写一个方法 用来返回代理类的对象
* @Title: getObjProxy
* @Description: TODO
* @param: @return
* @return: Object
* @throws */
public Object getObjProxy(){
//这个对象就是用来返回代理类对象的方法
Enhancer enhancer=new Enhancer();
//给代理了设置父亲
enhancer.setSuperclass(userDAO.getClass());
//设置调用的回调
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] arg2, MethodProxy arg3) throws Throwable {
System.out.println("植入了功能....");
Object objResult=method.invoke(userDAO, arg2);
System.out.println("植入了功能....1111");
return objResult;
}
});
//生成代理类
return enhancer.create();
}
}
@Test
public void testCglibProxy() throws Exception {
//获取代理类的对象
UserDAOProxy2 userDAOProxy=new UserDAOProxy2(new UserDAO());
//第二步:调用
UserDAO userDAO=(UserDAO) userDAOProxy.getObjProxy();
//第三步
userDAO.save();
}
6、基于代理和Filter的综合案例
「编码处理的问题:」
原理:过滤器技术拦截所有的controll的请求、在controll请求中使用了动态代理的设计模式监听了HttpServletRequest这个接口中getParameter方法的执行、在getParameter执行的时候、我们首先去获取这个数据、再通过判断当前的请求是GET还是POST、如果是GET那么先使用IOS-8859-1进行转码 然后使用UTF-8从新进行编码、如果是POST那么直接使用request.setCharacterEncoding(“UTF-8”)来进行处理
public class CharacterFilter implements Filter{
@Override
public void init(FilterConfig arg0) throws ServletException {
}
/**
* 拦截的这个方法 */
@Override
public void doFilter(ServletRequest request, ServletResponse response,
final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest req=(HttpServletRequest) request;
final HttpServletResponse resp=(HttpServletResponse) response;
//第一步:将返回数据的编码问题给处理了
resp.setContentType("text/html;charset=utf-8");
//POST的解决方案
req.setCharacterEncoding("UTF-8");
//第二步:监听httpServletRequest中 getParameter方法的执行
HttpServletRequest req1= (HttpServletRequest) Proxy.newProxyInstance(HttpServletRequest.class.getClassLoader(),
new Class[]{HttpServletRequest.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//监听当前执行的方法是不是 getParameter
String methodName=method.getName();
if("getParameter".equals(methodName)){ //说明执行的是getParameter
//判断当前执行的是POST呢?还是GET呢?
String reqName=req.getMethod();
//通过key获取这个值
String val= (String) method.invoke(req, args);
if("GET".equalsIgnoreCase(reqName)){ //说明是GET方法
//执行这个方法获取这个值
val=new String(val.getBytes("ISO-8859-1"),"UTF-8");
}else if("POST".equalsIgnoreCase(reqName)){ //说明是POST方法
}
//返回这个方法执行的结果
return val;
}else{
return method.invoke(req, args);
}
}
});
//最终要进行放行
chain.doFilter(req1, resp);
}
@Override
public void destroy() {
}
}
「字符和谐的问题:」
//需要和谐的脏数据
private String[] dirtyData={"MMD","NND","GD","CTM"};
protected String handleDirtyData(String val) {
for (int i = 0; i < dirtyData.length; i++) {
if(val.contains(dirtyData[i])){
val=val.replaceAll(dirtyData[i],"***");
}
}
return val;
}
结语
本篇关于过滤器Filter及代理Proxy的介绍就先到这里结束了,后续会出更多关于Filter和代理Proxy系列更多文章,谢谢大家支持!
Garnett还会不断的分享技术干货的,希望你们是我最好的观众!
乐于输出干货的Java技术公众号:Garnett的Java之路。公众号内有大量的技术文章、海量视频资源、精美脑图,不妨来关注一下!回复【资料】领取大量学习资源和免费书籍!