动态代理
用于拦截对目标对象的直接访问。代理对象具有自己的方法以及目标对象的全部方法,当被调用的是目标对象的方法时,代理对象先调用自己的方法,再让目标对象调用其对应的方法。
JavaAPI:
Proxy类产生代理对象,调用其静态方法newProxyInstance(ClassLoader,Interfaces[],InvocationHandler(Object proxy,Method method,Object[] args){})。这个静态方法中产生一个InvocationHandler类的内部类对象代表代理对象自己的方法;method代表被调用的方法,args代表方法参数。
条件:目标对象必须实现一个接口
示例代码:
/**
动态代理解决get方式乱码
**/
public class CharacterEncodingFilter implements Filter{
public void destroy() {
}
public void doFilter(ServletRequest req,ServletResponse resp,FilterChain chain) throws IOException,ServletException {
final HttpServletRequest request=(HttpServletRequest) req;
HttpServletResponse response=(HttpServletResponse) resp;
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
/**
在server.xml文件的8080端口下配置URIEncoding="UTF-8"也可解决get方式中文乱码
*/
chain.doFilter((ServletRequest)Proxy.newProxyInstance(CharacterEncodingFilter.class.getClassLoader(),request.getClass().getInterfaces(), new InvocationHandler() {
//产生Request的代理对象
public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
//拦截getParameter()方法 if(!method.getName().equals("getParameter")){
return method.invoke(request, args);
}
//post方式无需手动解决乱码,则调用真实对象的方法 if(request.getMethod().equalsIgnoreCase("post")){
return method.invoke(request, args);
}
//代理对象自己的方法,拦截get方式提交,解决get方式的乱码
String value=(String) method.invoke(request, args);
if(value==null){
return null;
}
return new String(value.getBytes("ISO8859-1"),"UTF-8");
}
}), response);
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}
2 注解+动态代理实现权限拦截
1)产生目标对象的代理对象,在代理对象的自己的方法中实现拦截。
示例:
public class ServiceFactory {
private static ServiceFactory factory=new ServiceFactory();
private ServiceFactory(){};
public static ServiceFactory getInstance(){
return factory;
}
public <T> T getBusinessService(Class<T> clazz,final User user) throws InstantiationException, IllegalAccessException{
final T t=clazz.newInstance();
return(T) Proxy.newProxyInstance(ServiceFactory.class.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//获取方法名称
String name=method.getName();
System.out.println(name);
//获取真实对象上的方法
Method m=t.getClass().getMethod(name, method.getParameterTypes());
//获取调用的方法上的注解
Permission p=m.getAnnotation(Permission.class);
//若注解为空,则无需权限,放行
if(p==null){
return method.invoke(t, args);
}
//需要权限,则得到注解内容并new出权限对象
String value=p.value();
Privilege pl=new Privilege();
pl.setName(value);
//判断用户是否登录,登录则得到用户拥有的权限
if(user==null){
throw new PrivilegeException("对不起,请先登录!");
}
BusinessService service=new BusinessService();
List<Privilege> list=service.findPrivileges(user.getId());
//判断需要的权限对象用户是否拥有
if(list.contains(pl)){
return method.invoke(t, args);
}else{
throw new PrivilegeException("对不起!您没有权限访问!");
}
//没有则抛出权限异常,拥有则放行
}
});
}
}
自己写的图书管理系统项目有这样的运用,有兴趣可看看案例源码