1、客户端请求一个HttpServletRequest的请求,如在浏览器中输入URL就是提交一个(HttpServletRequest)请求。
2、这个请求经过一系列的过滤器(Filter)如(ActionContextCleanUp、其他过滤器(SiteMesh等)、 FilterDispatcher)。注意:这里是有顺序的,先ActionContext CleanUp,再其他过滤器(Othter Filters、SiteMesh等),最后到FilterDispatcher。
FilterDispatcher是控制器的核心,就是MVC的Struts 2实现中控制层(Controller)的核心。
3、FilterDispatcher询问ActionMapper是否需要调用某个Action来处理这个(HttpServlet Request)请求,如果ActionMapper决定需要调用某个Action,FilterDispatcher则把请求的处理交给ActionProxy
4、ActionProxy通过Configuration Manager(struts.xml)询问框架的配置文件,找到需要调用的Action类。例如,用户注册示例将找到UserReg类
5、ActionProxy创建一个ActionInvocation实例,同时ActionInvocation通过代理模式调用Action。但在调用之前,ActionInvocation会根据配置加载Action相关的所有Interceptor(拦截器)。
6、一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果result
7、最后通过HTTPServletResponse返回客户端一个响应。
需要注意的是:
1、调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用
2、Struts 2的核心控制器是FilterDispatcher,有3个重要的方法:destroy()、doFilter()和Init(),可以在Struts 2的下载文件夹中找到源代码,执行顺序是:init()---- >doFilter()-------->destroy()
上面就大概的讲解一下struts2的工作流程,下面就讲下struts2的核心:
Struts2与前台交互的具体实现:
1.Struts2中的OGNL表达式 :
它可以用于,在JSP页面,使用标签方便的访问各种对象的属性;
它可以用于,在Action中获取传递过来的页面中的参数(并进行类型转换);
它还可以用在struts2的配置文件中
2.Struts2是通过ValueStack来进行赋值与取值的:
ValueStack实际上就是对OGNL的封装,OGNL主要的功能就是赋值与取值。
当 Struts 2接收到一个.action的请求后,调用拦截器链中的拦截器,当调用完所有的拦截器后,最后会调用Action类的Action方法,在调用Action方法之前,会建立Action类的对象实例,先将Action类的相应属性放到 ValueStack对象的顶层节点(ValueStack对象相当于一个栈)。只是所有的属性值都是默认的值,如String类型的属性值为null,int类型的属性值为0等。最后通过基本的getters方法,能够访问到某个对象的其它关联对象,并将 ValueStack对象顶层节点中的属性值赋给Action类中相应的属性。
Struts2中拦截器的动态代理以及AOP编程
动态代理:jdk代理和cglib代理
主要的区别是:
jdk代理必须要有接口和实现类:主要是为了绑定实现类对象并返回一个代理类
cglib代理是不需要接口的:直接通过传入实现类创建继承实现类子类代理对象。
这里我给大家演示jdk代理:
// 接口
public interface Dog {
public void info();
public void run();
}
//接口的实现类
public class DogImpl implements Dog {
@Override
public void info() {
System.out.println("one dog...");
}
@Override
public void run() {
System.out.println("can run...");
}
}
// 定义的拦截器 就是对调用狗的实现类方法的aop一些操作(方法的调用)
public class DogInterceptor {
// 第一个拦截方法
public void method1() {
System.out.println("first interceptor...");
}
// 第二个拦截方法
public void method2() {
System.out.println("second interceptor...");
}
}
单词英文意思:我的理解
// ProxyHandler Proxy代理 Handler处理程序 综合说:处理程序的代理为动态代理
// InvocationHandler Invocation调用 综合说 :调用处理程序的结果
// ProxyHandler类实现InvocationHandler 变成动态代理类
public class ProxyHandler implements InvocationHandler {
// 代理的目标对象
private Object target;
// 通过构造函数进行赋值
public ProxyHandler(Object target) {
super();
this.target = target;
}
// 创建狗拦截器的对象
DogInterceptor dogInterceptor = new DogInterceptor();
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// Object obj = null;
// /根据方法名调用不同的拦截器 这里代表拦截实现类里面的info方法不拦截run方法
if (method.getName().equals("info")) {
// before,狗拦截器里面的第一个拦截器
dogInterceptor.method1();
// 核心方法method.invoke(目标对象,args)
// obj第一个指参数明目标对象,要应用在哪个对象上
// args第二个参数指明要传入的参数
//类上面还有一个参数:Object proxy传入的这个参数实际是代理类的一个实例。我想可能是为了让程 //序员在invoke方法中使用反射来获取关于代理类的一些信息吧。
method.invoke(target, args);
// after,第二个拦截器
dogInterceptor.method2();
// 可以明显看出上面就是AoP,只是具体对象自己指定,然后这边负责创建代理对象,里面具体就是通过反射机制来创建代理对象
} else {
// 其他方法直接执行action
method.invoke(target, args);
}
return null;
//return null 这个你应该根据自己方法功能的情况,需要返回值时就定义Object去接收的方法,不许要则反之。
}
}
测试类
public class TestDog {
// 动态代理必须是接口的实现类
public static void main(String[] args) {
Dog dogImpl = new DogImpl();
// 创建返回狗的代理对象
// ClassLoader loader:指定要反射加载那个类对象
// Class<?>[] interfaces:要创建的对象,以对象集合方式放入
// InvocationHandler h指明动态代理的核心类
// 这里是jdk动态代理 要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)
Dog dogProxy = (Dog) Proxy.newProxyInstance(Dog.class.getClassLoader(),
new Class[] { Dog.class }, new ProxyHandler(dogImpl));
// 获得jdk动态代理创建的对象之后就可以调用对象里面的方法测试拦截器的应用,体验出aop的思想
dogProxy.info();// 被拦截的方法 在动态代理核心类里面进行判断设置
dogProxy.run();// 没有被拦截的方法
}、
}
唯一的疑惑点就是,调用dogProxy.info();怎么会调用这个类ProxyHandler的invoke方法呢?
咋们先看一下Proxy类中newProxyInstance方法的源代码:
public
static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h ==
null) {
throw
new NullPointerException();
}
/*
* Look up or generate the designated proxy class.
*/
Class cl = getProxyClass(loader, interfaces);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
/*
* Proxy源码开始有这样的定义:
* private final static Class[] constructorParams = { InvocationHandler.class };
* cons即是形参为InvocationHandler类型的构造方法
*/
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(
new Object[] { h });
}
catch (NoSuchMethodException e) {
throw
new InternalError(e.toString());
}
catch (IllegalAccessException e) {
throw
new InternalError(e.toString());
}
catch (InstantiationException e) {
throw
new InternalError(e.toString());
}
catch (InvocationTargetException e) {
throw
new InternalError(e.toString());
}
}
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)做了以下几件事.
(1)根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类.
(2)实例化$Proxy0并在构造方法中把DynamicSubject传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值,
class Proxy{
InvocationHandler h=
null;
protected Proxy(InvocationHandler h) {
this.h = h;
}
...
}
我们来看一下Proxy的子类$Proxy0的源代码:
public final class $Proxy0 extends Proxy implements Subject {
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
static { ss
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",
new Class[0]);
m3 = Class.forName("***.RealSubject").getMethod("request",
new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString",
new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
public $Proxy0(InvocationHandler invocationhandler) {
super(invocationhandler);
}
@Override
public final boolean equals(Object obj) {
try {
return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final int hashCode() {
try {
return ((Integer) super.h.invoke(this, m0, null)).intValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void request() {
try {
super.h.invoke(this, m3, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
接着把得到的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.request()方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。
1、需要说明的一点是,Proxy类中getProxyClass方法返回的是Proxy的Class类。
2、从$Proxy0的源码可以看出,动态代理类不仅代理了显示定义的接口中的方法,而且还代理了java的根类Object中的继承而来的equals()、hashcode()、toString()这三个方法,并且仅此三个方法。
【更多查看】
java中如何实现序列化,有什么意义java动态代理中的invoke方法是如何被自动调用的:http://www.tuicool.com/articles/VVRjIfU
struts2核心机制:http://blog.csdn.net/jy_he/article/details/52168653
转载请注明原文地址: https://ju.6miu.com/read-12236.html