静态代理模式:
简单的接受传入要被代理的对象,进行权限的设置,和是否允许被访问。
一般的做法是,实现和被代理类相同的方法,在方法中进行权限控制,判断是否有权限可以访问被代理类。
举例:
public interface SJSkill {
public void 吃();
public void 唱歌();
}
public class FBB implements SJSkill{
public void 吃(){
System.out.println("fbb吃饭。。。");
}
public void 唱歌(){
System.out.println("fbb唱歌。。。");
}
}
public class JJRStaticProxy implements SJSkill{
private FBB fbb = new FBB();
@Override
public void 吃() {
System.out.println("权限认证:你谁啊????");
fbb.吃();
System.out.println("记录日志:等我,我记一下来访记录");
}
@Override
public void 唱歌() {
System.out.println("权限认证:你谁啊????");
fbb.唱歌();
System.out.println("记录日志:等我,我记一下来访记录");
}
}
public class StaticProxyTest {
@Test
public void test01(){
JJRStaticProxy jjr = new JJRStaticProxy();
jjr.吃();
jjr.唱歌();
}
}
静态代理设计模式的优点:
结构清晰 易于理解
缺点:
如果被代理者有多个方法,则代理者也需要开发多个方法,其中往往存在大量重复代码,仍然存在代码重复。
动态代理:
jdk内置动态代理:
在jdk中提供了动态代理实现的工具类,直接使用该工具类就可以创建出代理者,并且可以通过内置的回掉函数指定代理在工作是的执行逻辑,从而实现基于jdk原生api的动态代理机制。
java.lang.reflect
类 Proxy
java.lang.Object
static Object | newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。 |
参数解释:
ClassLoader loader:用来生成代理者类的加载器,通常可以传入被代理者类的类加载器
interfaces:要求生成代理者实现的接口,通常就是实现和被代理者相同的接口,保证具有和被代理者相同的方法。
InvocationHandler:用来设定回调函数的回调接口,使用者需要写一个类实现此接口,从而实现其中的invoke方法,在其中编写代码处理代理者调用方法时的回调过程,通常在这里调用真正对象身上的方法,并且在方法之前和之后做额外的操作。
public class ProxyDemo {
@Test
public void ProxyTest(){
Start F=(Start)Proxy.newProxyInstance(FBB.class.getClassLoader(), FBB.class.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] a) throws Throwable {
//加权限操作
System.out.println(proxy.getClass());
System.out.println(method.getName());
System.out.println(Arrays.toString(a));
Object invoke = method.invoke(new FBB(), a);
return invoke;
}
});
F.song(1);
}
}
interface Start{
void song(int x);
}
class FBB implements Start{
@Override
public void song(int x) {
System.out.println(x+"fbb在唱K");
}
}
invoke参数解析:
proxy:代理者
method:当前调用的方法对象
a:当前调用者参数数组
java动态代理的特点:
优点:
不需要像静态代理一样被代理方法都要实现一遍,而只需要在回调函数中进行处理就可以了,重复代码减少。
缺点:
java的动态代理是通过代理者实现和被代理者相同的接口来保证两者具有相同的方法的,如果被代理者想要被代理的方法不属于接口,则生成的代理者自然无法具有这个方法,也就无法实现对该方法的代理。
总结:java的动态代理机制是基于接口进行的,受制于要代理的方法是否有接口的支持。
Cglib实现的动态代理:
Cglib是第3方提供的动态代理的实现工具,不管有没有接口都可以实现动态代理。
CGLIB实现动态代理的原理是生成的动态代理类是被代理类的子类,所以代理者具有和父类相同的方法,从而实现处理。
public class CglibDemo {
@Test
public void test1(){
//增强器
Enhancer en=new Enhancer();
//设定接口 --可以不设置
//en.setInterfaces();
//设定父类--此处要传入被代理者的类,此方法必须设置
en.setSuperclass(new FBB1().getClass());
//设定回调函数 -- 为增强器设定回调函数,之后通过增强器生成的代理对象
//调用任何方法都会走到此回调函数中,实现调用真正被代理对象的方法的效果
en.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] arg, MethodProxy mp) throws Throwable {
System.out.println(proxy.getClass());
System.out.println(method.getName());
System.out.println(Arrays.toString(arg));
System.out.println(mp.getSuperName());
return method.invoke(new FBB1(), arg);
}
});
FBB1 F=(FBB1)en.create();
F.song(1);
}
}
class FBB1{
public void song(int x) {
System.out.println(x+"fbb在唱K");
}
}
CGLIB动态代理的特点:
优点:无论是否有接口都可以实现动态代理,使用场景不受限制。
缺点:第三方提供的动态代理机制,不是原生的。