代理模式的作用
- 能够动态的给要执行的方法植入一段代码
- 动态的监听一个类里面某一特定方法的执行
代理模式的类型(三种)
静态代理
使用前提
被代理类必须实现接口,代理类必须实现与被代理类相同的接口
代码实现
package com.xyl.proxy;
/**
* Author:谢英亮
* Date:2018/1/27
* Time:9:41
* Description:公共的接口
*/
public interface IUser {
void eat();
void sleep();
}
package com.xyl.proxy;
/**
* Author:谢英亮
* Date:2018/1/27
* Time:9:42
* Description:被代理类
*/
public class User implements IUser {
@Override
public void eat() {
System.out.println("吃饭~~~~~");
}
@Override
public void sleep() {
System.out.println("睡觉~~~~~");
}
}
package com.xyl.proxy;
/**
* Author:谢英亮
* Date:2018/1/27
* Time:9:45
* Description:代理类
*/
public class UserProxy implements IUser {
private IUser user;
public UserProxy(IUser user) {
this.user = user;
}
@Override
public void eat() {
System.out.println("eat()方法正在执行");
user.eat();
System.out.println("eat()方法执行结束");
}
@Override
public void sleep() {
System.out.println("sleep()方法开始执行");
user.sleep();
System.out.println("sleep()方法执行结束");
}
}
package com.xyl.proxy;
/**
* Author:谢英亮
* Date:2018/1/27
* Time:9:48
* Description:测试静态代理
*/
public class TestProxy {
public static void main(String[] args) {
UserProxy userProxy=new UserProxy(new User());
userProxy.eat();
userProxy.sleep();
}
}
JDK代理
案例描述
- 在过滤器中使用JDK代理实现字符编码问题以及和谐关键字的功能
- 注:tomcat8及以上不需要处理乱码问题(我使用的是tomcat7进行测试的)
- JDK动态代理只能对实现了接口的类生成代理
代码实现
package com.xyl.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* Author:谢英亮
* Date:2018/1/26
* Time:17:41
* Description:处理乱码问题的过滤器以及文字的和谐(JDK代理)
*/
@WebFilter("/*")
public class CharFilter implements Filter {
//设置需要和谐的字符串数组
private String[] dirtyTalk = {"傻逼", "sb", "mmp", "cnm", "fuck"};
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//将req和resp强转为子类
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//设置相应编码
response.setContentType("text/html;charset=utf8");
//获取请求方法名字(GET POST等)
String requestMethod = request.getMethod();
InvocationHandler invocationHandler = (proxy, method, args) -> {
//获取当前方法的名字(不只是请求方法 还有其他方法)
String reqMethodName = method.getName();
//如果是getParamer()方法就进行处理
if ("getParameter".equals(reqMethodName)) {
String val = (String) method.invoke(request, args);
if ("GET".equalsIgnoreCase(requestMethod)) {
//设置编码格式
val = new String(val.getBytes("ISO-8859-1"), "UTF-8");
}
if ("POST".equalsIgnoreCase(requestMethod)) {
request.setCharacterEncoding("UTF-8");
}
//判断是否有需要和谐的字
for (String aDirtyTalk : dirtyTalk) {
if (val.contains(aDirtyTalk)) {
//将需要和谐的字替换成 **
val = val.replace(aDirtyTalk, "**");
}
}
return val;
} else {
return method.invoke(request, args);
}
};
//采用cglib代理 代理HttpServletRequest
HttpServletRequest req2 = (HttpServletRequest) Proxy.newProxyInstance(HttpServletRequest.class.getClassLoader(),
new Class[]{HttpServletRequest.class}, invocationHandler);
//一定得是给代理之后的对象放行
chain.doFilter(req2, resp);
}
public void init(FilterConfig config) {
}
}
cglib代理
案例描述
同上!!!
代码实现
package com.xyl.filter;
import net.sf.cglib.proxy.Proxy;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* Author:谢英亮
* Date:2018/1/27
* Time:8:47
* Description:处理乱码问题的过滤器以及文字的和谐(cglib代理)
*/
@WebFilter("/*")
public class TestFilter implements Filter {
//需要和谐的字符串
private String[] dirtyTalk={"mmp","cnm","傻逼","fuck"};
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//转换为子类对象
HttpServletRequest request = (HttpServletRequest) req;
//获取请求方法名字
String requestMethod = request.getMethod();
//设置响应的类型
resp.setContentType("text/html;charset=utf8");
//动态代理
HttpServletRequest servletRequest = (HttpServletRequest) Proxy.newProxyInstance(req.getClass().getClassLoader(),
new Class[]{HttpServletRequest.class},
(o, method, objects) -> {
//获取方法的名字
String methodName = method.getName();
Object invoke = method.invoke(request, objects);
//判断是否为getParameter()方法
if ("getParameter".equals(methodName)) {
String val = (String) invoke;
//判断是什么请求
if ("GET".equalsIgnoreCase(requestMethod)) {
//设置编码格式
val = new String(val.getBytes("ISO-8859-1"), "UTF-8");
}
if ("POST".equalsIgnoreCase(requestMethod)) {
//设置编码格式
request.setCharacterEncoding("UTF-8");
}
//和谐字符串
for(String dirty:dirtyTalk){
//判断是否有需要和谐的字段
if(val.contains(dirty)){
//替换
val= val.replace(dirty,"**");
}
}
return val;
}
return invoke;
});
chain.doFilter(servletRequest, resp);
}
public void init(FilterConfig config) {
}
}
小结
- 静态代理中被代理类必须要实现接口而且代理类也必须实现与被代理类相同的接口
- JDK代理只能针对于实现了接口的类
- cglib代理针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)
- 在spring中,当Bean实现了接口时采用的是JDK代理,当Bean没有实现接口时采用的是cglib代理
- 使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。