>一个例子 房客租房子:
---------------------------------------------------------------------------------
中介要遵循一定的规范:接口 Premises 类
---------------------------------------------------------------------------------
中介:Rent 类
出租房屋功能:rent() ,但执行出租房屋的功能,房东来执行
---------------------------------------------------------------------------------
房东:Houser类
出租房屋功能:rent()
---------------------------------------------------------------------------------
房客:Client类
---------------------------------------------------------------------------------
>静态代理(百无一用,用就用动态)
Houser:
public class Houser implements Preises{
public void rent() {//领域业务 更纯粹
System.out.println("出租房屋!");
}
}
Rent:
public class Rent implements Preises {
private Houser houser=new Houser();
private void haveLook(){
System.out.println("带房客看房!");
}
@Override
public void rent() {//实际开发过程中:领域业务、公共业务
this.haveLook();
houser.rent();
this.money();
}
private void money(){
System.out.println("收取中介费!");
}
}
Premises:
public interface Preises {
public void rent();
}
Client:
public class Client {
public static void main(String[] args) {
Rent rent=new Rent();
rent.rent();
}
}
角色类型:领域业务,Houser
代理角色:Rent,中介
抽象角色:接口
好处:在开发过程中,让领域业务更加纯粹,不与其他业务耦合。
缺点:增加了开发的复杂度,每有一个领域业务(真实角色),就要针对该领域业务,再写一个代理角色。
>动态代理:(代理角色不再去实际创建,而是去动态生成)
作用:动态的去修改一个已经存在的类的方法
(再说下反射:可以通过java代码,解析另外的java代码,自己解析自己
想象一下,一个方法go(String className,String methodName){
//在这个go方法里,如何根据类名,方法名调用传入类名类的指定名称方法?
//答:反射!})
两种方式(推荐使用cglib):
基于接口的动态代理:jdk(不需要依赖第三方类库)
基于类的动态代理:cglib
>基于接口的动态代理:
(反射:自己分析自己,java通过反射可以分析一个类的结构,可以执行一个类的方法)
在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理或动态代理对象。
代理类是在内存中生成的。
>hello jdk 动态代理
AInterf接口:
package com.langsin.testProxy;
public interface AInterf {
public void f1();
public void f2();
}
AImpl实现:
public class AImpl implements AInterf {
@Override
public void f1() {
System.out.println("f1");
}
@Override
public void f2() {
System.out.println("f2");
}
}
代理生成类:
public class ProxyBuilder implements InvocationHandler{
private AInterf a;
public ProxyBuilder(AInterf a) {
this.a=a;
}
public AInterf bind(){
//Proxy类的newProxyInstance方法 就是要创建一个类 (这个类:第一,也是AInterf接口的实现类;第二,还是AImpl的动态代理类,实现代理功能)
//为什么要让生成的这个家伙(代理)也去实现 AInterf ? 因为在内存中压根就没有一个类能接收它
return (AInterf) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{AInterf.class}, this);
// 参数: 当前类的类加载器 (当前工程所有都是同一个类加载器) 返回值(dynamic代理类)要实现的接口 InvocationHandler对象
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result=null;
if ("f1".equals(method.getName())) {
System.out.println("你没有权限!");
}
if ("f2".equals(method.getName())) {
System.out.println("欢迎光临!");
System.out.println("before");
result=method.invoke(a, args);//放行原始类的方法执行
System.out.println("after");
}
return result;
}
}
测试类:
public class Run {
public static void main(String[] args) {
AInterf a=new AImpl();
AInterf ap = new ProxyBuilder(a).bind();
//这里ap 接收了代理类的父类对象 调用的是代理类中 的 f1 f2方法
//而且 每次调用 都会去走ProxyBuilder的 invoke方法
ap.f1();
ap.f2();
}
}
练习:比如当调用ArrayList的以add名字开头的方法时,去打印一句话,怎么做?
public class ProxyBuilder implements InvocationHandler{
private List list;
public ProxyBuilder(List list) {
this.list=list;
}
public List bind(){
//Proxy类的newProxyInstance方法 就是要创建一个类 (这个类:第一,也是AInterf接口的实现类;第二,还是AImpl的动态代理类,实现代理功能)
//为什么要让生成的这个家伙(代理)也去实现 AInterf ? 因为在内存中压根就没有一个类能接收它
return (List) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{List.class}, this);
// 参数: 当前类的类加载器 (当前工程所有都是同一个类加载器) 返回值(dynamic代理类)要实现的接口 InvocationHandler对象
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result=null;
if (method.getName().startsWith("add")) {
System.out.println("欢迎添加数据!");
method.invoke(list, args);
}else {
result=method.invoke(list, args);//放行原始类的方法执行
}
return result;
}
}
>基于cglib的动态代理:
基于jdk的Proxy的局限性:被代理的那个哥们,必须要实现一个接口。
ForumServiceImpl
package com.langsin.cglibproxy;
public class ForumServiceImpl {
public void removeTopic(int topicId) {
System.out.println("模拟删除Topic记录:"+topicId);
}
public void removeForum(int forumId) {
System.out.println("模拟删除Forum记录:"+forumId);
}
}
CglibProxy
package com.langsin.cglibproxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("检查权限");
Object result = proxy.invokeSuper(obj, args);
System.out.println("善后处理");
return null;
}
}
TestForumService
package com.langsin.cglibproxy;
public class TestForumService {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
ForumServiceImpl forumService = (ForumServiceImpl)proxy.getProxy(ForumServiceImpl.class);
forumService.removeForum(10);
forumService.removeTopic(1023);
}
}