使用这种方式必须满足的条件是:被增强的方法的所在类能被继承,并且这个对象已经明确知道。
举例:
有一个接口Person,里面有一个方法run()
package com.itzhouq.demo1;
public interface Person {
public void run();
}
类NormalPerson实现了这个接口Person
package com.itzhouq.demo1;
public class NormalPerson implements Person {
@Override
public void run() {
System.out.println("走.......");
}
}
现在的需求是,使用继承方式增强NomalPerson中的方法run()
这里需要被增强的方法是run(),所在的类NomalPerson可以被继承并且已经明确。
所以创建一个类Superson继承NormalPerson
package com.itzhouq.demo1;
public class Superson extends NormalPerson {
//重写了父类NormalPerson的方法
@Override
public void run() {
super.run();
System.out.println("增强了,变成飞了。。。");
}
}
类Superson通过对父类NormalPerson的run()方法进行重写,实现对run()方法的增强。
测试
package com.itzhouq.demo1;
import org.junit.Test;
/*
* 增强一个对象的方法之一:继承方式
*/
public class Demo {
@Test
public void test() {
NormalPerson p = new NormalPerson();
p.run();//走.......
}
//需求:对普通人的run方法进行增强,由走变成飞----增强一个对象的方法
//用继承来实现需求:创建一个类继承NormalPerson
@Test
public void test2() {
Superson superson = new Superson();
superson.run();
// 走.......
// 增强了,变成飞了。。。
}
}
装饰者模式实现对方法的增强,不需要知道被增强的方法run()所在的类是哪个类,只需要知道这个类实现了哪个接口即可。
条件:
接口:
package com.itzhouq.demo2;
public interface Person {
public void run();
}
需要被增强的方法run()
package com.itzhouq.demo2;
public class NormalPerson implements Person {
@Override
public void run() {
System.out.println("走.......");
}
}
这里被装饰者就是run()方法所在的类
创建一个装饰者类,实现run()所在类,实现的接口Person
package com.itzhouq.demo2;
public class Superson implements Person {
//被装饰者的引用
private NormalPerson p;
public Superson(NormalPerson p) {
this.p = p;
}
@Override
public void run() {
//这个是被装饰者以前的方法
p.run();
//增强
System.out.println("增强了,变成飞。。。。");
}
}
测试
package com.itzhouq.demo2;
import org.junit.Test;
/*
* 增强一个对象的方法之二:装饰者方式
*/
public class Demo {
@Test
public void test() {
NormalPerson p = new NormalPerson();
p.run();//走.......
}
//需求:对普通人的run方法进行增强,由走变成飞
//假装不知道接口的实现类NormalPerson,但是要对普通人的run方法进行增强
//不知道实现类就无法使用继承的方式进行增强
//使用装饰者解决这样的问题:
//条件1:装饰者()和被装饰者()实现同一个接口Person
//条件2:装饰者里面有被装饰者的引用 在我出生的时候,你把你给我,我对你进行增强
@Test
public void test2() {
NormalPerson p = new NormalPerson();
Superson superson = new Superson(p);
superson.run();
// 走.......
// 增强了,变成飞。。。。
}
}
通过一张图回顾动态代理
动态代理的条件:必须知道要被代理的类/对象是谁,这里要被代理的类是NoemalPerson
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interface, InvocationHander h);
//返回一个指定接口的代理类实现
接口person,这里再加一个方法sleep
package com.itzhouq.demo3;
public interface Person {
public void run();
public String sleep();
}
实现类NomalPerson
package com.itzhouq.demo3;
public class NormalPerson implements Person {
@Override
public void run() {
System.out.println("走.......");
}
@Override
public String sleep() {
System.out.println("睡觉了。。。");
return "sleep";
}
}
使用动态代理增强
package com.itzhouq.demo3;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.junit.Test;
public class Demo {
@Test
public void test() {
NormalPerson p = new NormalPerson();
p.run();//走.......
}
//需求:使用动态代理的方式对普通人进行增强
//JDK提供的类和方法可以给咱们动态的生成代理对象/增强对象
/*
* 参数概述:固定的
* 参数1:和要被增强的对象,一样的,类加载器
* 参数2:和要被增强的对象一样的接口
* 1 根据指定的传递接口返回一个该接口下的实例
* 2 传递的接口里面的方法就是可以被增强的所有方法
* 参数3:所有的增强业务的逻辑实现(方法)
*/
@Test
public void test1() {
NormalPerson p = new NormalPerson();
Person proxyPerson = (Person) Proxy.newProxyInstance(
p.getClass().getClassLoader(),
p.getClass().getInterfaces(),
new InvocationHandler() {
/*
* 参数概述:固定的
* 参数1:不用管,永远是固定值 代理对象的类型
* 参数2:要被增强的方法
* 参数3:要被增强的方法运行过程中需要的参数
*/
@Override //invoke里面是所有的增强业务的逻辑代码
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//让以前的方法执行
//参数1:本身应该执行这个方法的对象
//参数2:执行这个方法需要的参数
Object value = method.invoke(p, args);
//原来方法的返回值
System.out.println(value);
// 写增强业务逻辑
System.out.println("增强了,变成飞了。。。");
//最终的返回值,谁调用返回给谁
return "abcd";
}
});
proxyPerson.run();//执行接口中的每一个需要增强的方法,invoke都会执行一遍,执行的内容就是针对该方法的增强
// 走.......
// 增强了,变成飞了。。。
String value = proxyPerson.sleep();
System.out.println(value);
// 睡觉了。。。
// sleep
// 增强了,变成飞了。。。
// abcd
}
}
新建Web项目,新建一个index.jsp。在JSP中写两个表单,分别为post和get方式提交。后台通过Servlet接收到前台输入的username,打印在控制台会乱码。
JSP
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
Servlet
package com.itzhouq.web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletDemo1 extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
System.out.println(username);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
为解决这个问题使用过滤器,在过滤器中使用动态代理方式解决
新建一个过滤器MyFilter.java,并在xml文件中配置过滤的资源为全部资源
web.xml
<filter>
<filter-name>MyFilterfilter-name>
<filter-class>com.itzhouq.filter.MyFilterfilter-class>
filter>
<filter-mapping>
<filter-name>MyFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
MyFilter
package com.itzhouq.filter;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
public class MyFilter implements Filter {
public MyFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//要增强的方法:request.getparameter
//被代理的对象:request
HttpServletRequest request = (HttpServletRequest)req;
//动态的生成代理对象
HttpServletRequest hsr = (HttpServletRequest) Proxy.newProxyInstance(
request.getClass().getClassLoader(),
request.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//1. 判断是否是要增强的方法getParameter
if("getParameter".equals(method.getName())) {
//知道getParameter使用的是哪个提交方式
String m = request.getMethod();
//判断是get还是post
if("get".equalsIgnoreCase(m)) {
// 以前方法调用后的乱码
String s = (String)method.invoke(request, args);
// 增强---解决乱码
s = new String(s.getBytes("iso8859-1"),"utf-8");
return s;
}
if("post".equalsIgnoreCase(m)) {
request.setCharacterEncoding("utf-8");
return method.invoke(request, args);
}
}
// 如果是别的方法
return method.invoke(request, args);
}
});
chain.doFilter(hsr, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
后台Servlet接收到的username不在乱码。