您的位置:首页 > 运维架构

(入门)什么是AOP?什么是代理模式?怎么设计日志拦截器?

2017-01-05 00:00 696 查看
什么是AOP(Aspect Oriented Programming)?
  面向切面编程(也叫面向方面编程):Aspect Oriented Programming(AOP),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。



  主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等。
  主要的意图是:将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改 变这些行为的时候不影响业务逻辑的代码。
  AOP的底层实现技术是JDK动态代理。可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式(GoF强调的是接口或抽象类在实际案例中的灵活应用和智慧)的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可以说也是这种目标的一种实现。

代理模式Proxy Pattern,23种java常用设计模式之一。代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问。代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。
-----------------------------------------------------------------------------------------
//Junit测试类
@Test
public void testProxy() {
UserDAO userDAO = new UserDAOImpl();//新建被拦截类
LogInterceptor li = new LogInterceptor();//新建日志拦截器
li.setTarget(userDAO);//把被拦截的类添加到拦截器里面去
UserDAO userDAOProxy = (UserDAO)Proxy.newProxyInstance
(userDAO.getClass().getClassLoader(),
userDAO.getClass().getInterfaces(), li);//根据拦截器生成代理类,下面有解释
System.out.println(userDAOProxy.getClass());//输出代理类的名
userDAOProxy.save(new User());//往代理类进行操作
userDAOProxy.delete();
}
-----------------------------------------------------------------------------------------
//LogInterceptor日志拦截类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
//拦截器类要继承自InvocationHandler,InvocationHandler 是代理实例的调用处理程序实现的接口
public class LogInterceptor implements InvocationHandler {
private Object target;
//拦截器的setter和getter方法
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
//Method是方法,beforeMethod就是方法在执行之前的方法
public void beforeMethod(Method m) {
System.out.println(m.getName() + " start");
}

//Object invoke(Object proxy, Method method, Object[] args) 方法是在代理实例上处理方法调用并返回结果。每个代码实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。也就是说:调用一个功能,不直接调用原类而去调用它的代理,代理通过反射机制找到它的这个功能的方法。然后代理自己去执行,所以invoke()会自动执行.
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
beforeMethod(m);
m.invoke(target, args);//关于加不加这句请看下面分析
return null;
}
}
-----------------------------------------------------------------------------------------
//加m.invoke(target, args)的输出结果:
class $Proxy4
save start
user saved!
save start
user saved!
save start
user saved!
delete start
user deteleted
//不加m.invoke(target, args)的输出结果:
class $Proxy4
save start
save start
save start
delete start
//save start是beforeMethod()的输出,
user saved是UserDAOImpl的save()的输出。不知道怎么解释了?求大神,大家帮忙。意会意会一下.....

*。关于代理类,JDK 中具体的动态代理类是怎么产生的呢?

1.产生代理类$Proxy0 类:
执行了 Proxy. newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)将产生$Proxy0 类,它继承Proxy 对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode ,toString 和equals 三个方法),但是还没有具体的实现体。

2.将代理类$Proxy0类加载到JVM中,这时候是根据 Proxy. newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 它的第一个参数---- 就是被代理类的类加载器,把当前的代理类加载到JVM 中。

3.创建代理类$Proxy0类的对象,调用的$Proxy0类的$Proxy0 (InvocationHandler )构造函数,生成$Proxy0 类的对象,参数就是 Proxy. newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 它的第三个参数,这个参数就是我们自己实现的InvocationHandler 对象,我们知道InvocationHandler 对象中组合加入了代理类代理的接口类的实现类;所以,$Proxy0 对象调用所有要实现的接口的方法,都会调用InvocationHandler 对象的invoke ()方法实现。

4.生成代理类的class byte,动态代理生成的都是二进制class 字节码。

⊙_⊙最后,按照我的惯例,附上本次的项目源码,类库用到三个(spring.jar junit.jar(eclipse自带) commons-logging.jar 缺少类库到http://moshowgame.iteye.com/admin/blogs/1606825下载)。
^_^还有什么好方法或者疑问和意见欢迎大家提出来一起讨论!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息