1、AOP介绍
AOP(Aspect-Oriented Programming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。
而AOP技术则恰恰相反,它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,利用了jdk动态代理技术,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。
2、静态代理模式实现AOP
- 接口类IHello:
public interface IHello
{
void sayHello(String str);
void sayBye();
}
- 实现类Hello:
public class Hello implements IHello{
@Override
public void sayHello(String str) {
System.out.println("hello : "+str);
}
@Override
public void sayBye() {
System.out.println("bye bye");
}
}
- 代理类ProxyHello:
/*
* 静态代理模式实现AOP
*/
public class ProxyHello implements IHello {
private IHello target;
public ProxyHello(IHello target)
{
this.target=target;
}
@Override
public void sayHello(String str) {
// TODO Auto-generated method stub
Logger.start(); //Logger类,打印日志信息
target.sayHello(str);// 调用被代理对象的方法
Logger.end();
}
@Override
public void sayBye() {
target.sayBye();
}
}
- main函数:
public class TestStaticProxy {
public static void main(String[] args) {
// TODO Auto-generated method stub
IHello target=new Hello();
//target.sayHello("just a demo");
target = new ProxyHello(target);
target.sayHello(" kitty");
System.out.println("*************************");
target.sayBye();
}
}
3、动态代理模式实现AOP
代理类:
public class DynDemo implements InvocationHandler
{
private Object obj;// 此时OBJ是要被代理的对象
private BeforeMethod befor;
public DynDemo()
{
}
// 此时参数obj是要被代理的对象
public DynDemo(Object obj)
{
this.obj = obj;
}
// 此时参数obj是要被代理的对象
public DynDemo(Object obj,BeforeMethod befor)
{
this.obj = obj;
this.befor=befor;
}
//这个方法不是我们显示的去调用
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
System.out.println(method.getName());
if(method.getName().equals("hello"))
{
return method.invoke(obj, args); //真正的调用它原对象
}
// System.out.println("before calling " + method);
if(befor!=null)
befor.say();
//System.out.println(this.obj);
Object result= method.invoke(obj, args); // 执行被代理对象的切入点
// obj.say(args);
System.out.println("after calling " + method);
return result;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public BeforeMethod getBefor() {
return befor;
}
public void setBefor(BeforeMethod befor) {
this.befor = befor;
}
}
该代理类的作用:通过被代理的对象,确认切入点,增加额外的操作。
客户端:
//客户端:生成代理实例,并调用了say()方法
public class TestDemo {
public static void main(String[] args) throws Throwable{
// TODO Auto-generated method stub
Demo target=new Demo();//这里指定被代理类
InvocationHandler ds=new DynDemo(target);
System.out.println(ds);
Class<?> cls=target.getClass();// 获取target对象类的字节码
//以下是一次性生成代理
IDemo subject=(IDemo)Proxy.newProxyInstance(
cls.getClassLoader(),cls.getInterfaces(), ds);
//这里可以通过运行结果证明subject是Proxy的一个实例,这个实例实现了IDemo接口
System.out.println(subject instanceof Proxy);
//这里可以看出subject的Class类是$Proxy0,这个$Proxy0类继承了Proxy,实现了IDemo接口
// System.out.println("subject的Class类是:"+subject.getClass().getName());
// System.out.println("subject的Class父类是:"+subject.getClass().getSuperclass()
// .getName());
/* System.out.println("\n"+"subject实现的接口是:");
Class<?>[] interfaces=subject.getClass().getInterfaces();
for(Class<?> i:interfaces){
System.out.println(i.getName());
}
System.out.println("subject中的属性有:");
Field[] field=subject.getClass().getSuperclass().getDeclaredFields();
for(Field f:field)
{
System.out.print(f.getName()+", "+f.getType()+" # ");
f.setAccessible(true);
System.out.println(f.get(subject)+" #"+f.getModifiers());
} */
System.out.println("subject中的方法有:");
Method[] method=subject.getClass().getDeclaredMethods();
for(Method m:method){
System.out.print(m.getName()+", ");
}
/*
*/
System.out.println("\n\n"+"运行结果为:");
subject.say();
subject.hello();
}
}
通过 Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), ds)
方法,一次性生成代理,并通过返回的对象调用重写的方法。
Proxy.newProxyInstance()
的具体实现逻辑:
public class MyProxy implements IDemo
{
private DynDemo target;
public MyProxy(DynDemo target)
{
this.target=target;
}
@Override
public void say() {
// TODO Auto-generated method stub
try {
Method method=target.getObj().getClass().getDeclaredMethod("say", null);
target.invoke(null, method, null);
}catch(Throwable e)
{
e.printStackTrace();
}
}
@Override
public void hello() {
// TODO Auto-generated method stub
}
}
4、小结
4.1 静态代理模式下的AOP实现
通过一个实现接口的代理类,可以在不影响用户操作的时候添加其它功能,如记录日志等。
4.2 动态代理模式下的AOP实现
代理类可以动态地获取被代理的对象,通过该对象获取切入点,并添加操作。然后通过客户端实现被代理类的接口,调用Proxy.newProxyInstance()
方法获取代理实例,并通过该方法返回的实例对象调用重写后的方法。
Proxy.newProxyInstance()
完成的功能:
生成一个类(Proxy的子类);Proxy$0
Proxy$0类会重写被代理类的接口。
每个方法调用中间代理类的invoke。