先提一下反射的概念:
反射(Reflection):在程序编译的时候先不指定某个东西,然后在运行的时候再指定。反射被视为动态语言的关键。反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任何对象的内部属性及方法。
Java反射提供的功能:
1、 在运行时判断任意一个对象所属的类
2、 在运行时构造任意一个类的对象
3、 在运行时判断任意一个类所具有的成员变量和方法
4、 在运行时调用任意一个对象的成员变量和方法
5、 生成动态代理
为什么要动态代理?
在实际的开发中,总会存在相同的代码段重复出现的情况,在这种情况下,有种捷径就是选中那些相同的代码,然后通过“复制,粘贴”得的方式,完成软件开发。但是如果有一天需要对这些相同的代码完成修改的话,那就得在每一段包含这些相同代码的源代码进行修改,这需要耗费大量的时间。
下面是个实例图:
最理想的效果就是:代码块1、代码2和代码3既可以执行深色代码部分,又无须在程序中以硬编码方式直接调用深色代码的方法,这时候就可以通过动态代理来达到这种效果。
下面是一个代码例子:
//定义一个接口
interface Human{
void info();
void fly();
}
//定义一个Human接口的实现类,为被代理类
class Superman implements Human
{
@Override
public void info()
{
System.out.println("我是超人!");
}
@Override
public void fly()
{
System.out.println("我会飞!");
}
}
//创建一个包含两个方法固定的类
class HumanUtil
{
public void method01()
{
System.out.println("========方法一=======");
}
//想在这两个方法中间动态的插入一个方法
public void method02()
{
System.out.println("========方法二=======");
}
}
//动态代理
class TestInvocationHandler implements InvocationHandler{
Object obj;//实现了接口的被代理类的对象的声明
//通过这个方法传入一个Object obj对象
//给被代理类的对象实例化;
public void setObject(Object obj)
{
this.obj = obj;
}
@Override
//返回一个代理类的对象
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
HumanUtil h = new HumanUtil();
//调用method01
h.method01();
//在method01和method02中间插入了一个方法,这个方法是动态的
Object returnVal = method.invoke(obj,args);
h.method02();
return returnVal;
}
}
//创建一个被代理类的对象,作用是动态地创建一个代理类对象
class MyProxy
{
public static Object getProxyInstance(Object obj)
{
TestInvocationHandler handler = new TestInvocationHandler();
handler.setObject(obj);
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
}
}
//测试类
public class TestAOP
{
public static void main(String[] args)
{
//创建了一个被代理类的对象
Superman man = new Superman();
//返回man的代理对象
Object obj = MyProxy.getProxyInstance(man);
//因为代理类对象返回的man对象是实现了Human接口的,所以可以进行一个转型
Human hu = (Human)obj;
//通过代理类的对象调用重写的抽象方法
hu.info();
System.out.println();
hu.fly();
}
}
上面的代码例子中,HumanUtil方法一和方法二相当于相同的代码块。而当需要不同实现功能的代码块时,我们可以利用代理类对象动态的插入不同实现功能的代码块。
动态代理的实现步骤:
1、 首先包中存在被代理类
2、 创建一个代理类实现InvocationHandler接口,将被代理类传入该代理类中,创建一个set()实例化被代理类,并重写invoke()方法,返回一个被代理类对象。
3、 在main方法中创建一个代理类对象,实例化代理类对象A,将A作为参数传入Proxy类的newProxyInstance()方法中。
4、 返回的Proxy对象进行强制转换,得到的那个对象就可以当成被代理类了。
下面是AOP代理的方法与目标对象的方法示意图
而面向切面编程相当于在HumanUtil固定的方法一和方法二当中插入我们想要的其他功能的代码。