代理的定义:给目标对象提供一个代理对象,并且由代理对象控制着目标对象的引用
目的:
1)功能增强,通过代理对象对原业务进行增强。
2)控制访问,通过代理对象间接访问目标对象,防止直接访问目标对象给系统带来不必要复杂性
怎么实现代理?
有两种方式:
1)静态代理:
2)动态代理:动态代理有两种方式,一种是基于jdk动态代理,另一种是spring框架里的cglib动态代理。
静态代理:利用接口实现静态代理
先通过接口定义好我们需要代理的方法,再写一个代理类来实现我们要代理的目标对象有哪些,等要实现一个目标对象时我们需要添加一个目标对象,再把目标对象在代理类里进行实例化。我们看以下例子:
根据上面所说,先写一个接口(生产衣服的接口),定义需要代理的方法:
public interface Byclothes {
public void clothes(String size);
}
再写一个代理类:
public class Daili implements Byclothes{
@Override
public void clothes(String size) {
// TODO Auto-generated method stub
//实现的接口方法,在需要代理时可以调用
}
public void start() {
System.out.println("前置服务");
}
public void end() {
System.out.println("后置服务");
}
}
这时我们需要生产一件衣服,要通过代理类进行代理,我们写一个目标类clothA:
public class ClothA implements Byclothes{
@Override
public void clothes(String size) {
// TODO Auto-generated method stub
System.out.println("你添加了一件"+size+"的衣服");
}
}
此时我们需要代理类来进行代理,我们就需要在代理类里进行实例化,再在方法里进行具体实现,我们看以下代码:
public class Daili implements Byclothes{
private ClothA a=new ClothA();
@Override
public void clothes(String size) {
// TODO Auto-generated method stub
start();
a.clothes(size);
end();
}
public void start() {
System.out.println("前置服务");
}
public void end() {
System.out.println("后置服务");
}
}
我们发现静态代理很麻烦,每当需要添加一个目标对象时,我们都需要进行大量的代码整理,违背了开闭原则,所以一般都通过动态代理进行实现代理。
基于jdk的动态代理:
基于jdk的动态代理里用到了jdk里封装好的一个接口,叫做InvocationHandler,我们通常在代理类里来实现这个接口,再来实现接口里的invoke方法,反射里经常用到invoke来调用方法,这里是同样的道理。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
}
看如上代码,invoke方法里proxy代表要代理的目标类,method代表目标类中的方法,args代表目标类当中的方法参数。
通过上面的解释,我们需要在这个从接口里继承来的invoke方法里用method.invoke(创建的目标类, args);这个方法来调用我们的目标类的方法。
我们还用之前写的bycloth接口和clothA目标类,
我们写的代理类如下:
public class ProxyFactory implements InvocationHandler{
private Object factory ; //被代理对象的引用
public Object getFactory(){
return factory;
}
public void setFactory(Object factory){
this.factory = factory;
}
//反射执行方法
//1.Object :jdk创建的代理类,无需赋值
//2.Method : 目标类当中的方法,jdk提供,不需要赋值
//3.Object[]:目标类当中的方法参数 ,jdk提供,不需要赋值
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
FrontService();
method.invoke(factory,args);//执行目标类当中的方法
endService();
return null;
}
//该方法并不是固定的,但是内部的Proxy类的创建是核心
/**
* 1.ClassLoader loader : 类的加载器:像内存当中加载对象,使用反射的方式获取
* 2.Class<?>[] interfaces:获取目标类的接口,使用反射的方式获取---------》方法
* 3.InvocationHandler h:让代理类知道被代理的方法
* @return
*/
public Object getProxyInstance() {
// TODO Auto-generated method stub
return Proxy.newProxyInstance(factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), this);
}
public void FrontService() {
System.out.println("根据您的需求进行市场调研");
}
//前置服务
public void endService() {
System.out.println("为您提供一条龙的包办服务");
}
}
我们定义的getproxyinstance方法是整个代理类的核心,用来调用invoke方法
我们再用test类对代理类进行测试:
public class Test {
public static void main(String[] args) {
ProxyFactory proxyFactory=new ProxyFactory();
ClothA A=new ClothA();
proxyFactory.setFactory(A);
Byclothes byclothes=(Byclothes)proxyFactory.getProxyInstance();
byclothes.clothes("xxl");
}
}
输出结果如下:
如果再添加需要代理的目标类时,我们直接在test类里进行调用就可以而不用再在代理类里再写。