无法访问目标对象,通过代理对象进行访问,而且增强式的访问。适合进行业务的拓展
代理模式的作用
1、控制目标对象的访问
2、增强功能
代理模式的分类
1、静态代理
2、动态代理,又分为JDK动态代理,CGLib动态代理
静态代理
它是代理模式的一种,具备以下特点:
1)目标对象和代理对象实现同一个业务接口
2)目标对象必须实现接口
3)代理对象在程序运行前就已经存在
4)静态代理能够灵活地进行目标对象的切换,却无法进行功能的灵活处理(使用动态代理处理此问题)
静态代理功能实现
业务功能:请明星进行节目表演,
明星刘德华:目标对象(无法直接访问)
经纪人:代理对象(我们可以访问到,跟目标对象对接)
我们 :客户端对象
public class MyTest {
//测试功能
@Test
public void testAgent(){
/* Agent agent=new Agent();
agent.sing();
//有接口和实现类,必须使用接口指向实现类(规范)
*/
Service agent=new Agent();
agent.sing();
}
面向接口编程
类中的成员变量设计为接口,方法的形参设计为接口,调用时接口指向实现类
测试类
@Test
public void testAgent1(){
Service agent=new Agent(new SuperStarLiu());
agent.sing();
}
接口
public interface Service {
//规定唱歌的业务功能
void sing();
}
代理
package com.service;
/*
* z助力:代理对象 完成除了唱歌主业务之外的其他业务 时间
* 场地 结算 费用
*
* 类中的成员变量设计为接口
* */
public class Agent implements Service{
public Service target;//目标对象
//传入目标对象 方法的参数设计为接口
public Agent(Service target){
this.target=target;
}
@Override
public void sing() {
System.out.println("预定时间");
System.out.println("预定场地");
//切记切记:业务功能必须由目标对象亲自实现
// 面向接口编程的调用时接口指向实现类
target.sing();
System.out.println("结算费用");
}
}
目标对象
/*
* 目标对象
*
* */
public class SuperStarZhou implements Service{
@Override
public void sing() {
System.out.println("我是周润发");
}
/*
* 目标对象 :实现业务接口中的功能 进行唱歌表演
* */
public class SuperStarLiu implements Service{
@Override
public void sing() {
System.out.println("我是华仔,我正在唱歌");
}
}
动态代理
代理对象在程序运行过程中动态在内存构建,可以灵活的进行业务功能的切换
JDK动态代理
1)目标对象必须实现业务接口
2)JDK代理对象不需要实现业务接口
3)JDK动态代理的对象在程序运行前不存在,在程序运行时动态的在内存中构建
4)JDK动态代理灵活地进行业务功能的切换
5)本类中的方法(非接口中的方法)不能被代理(代理不允许本人接私活)
JDK动态代理用到的类和接口
它是使用现成的工具类完成动态实现。
1)Proxy类 它是java.lang.reflect.Proxy包下的类 它有一个方法
Proxy.newProxyInstance()专门用来生成动态代理对象
ClassLoader loader 类加载器,完成目标对象的加载 Class<?>[] interfaces 目标对象实现的所有接口 InvocationHandler h 实现代理功能的接口,我们传入的是匿名内部实现
2)Method类
反射用的类,用来进行目标对象的方法的反射调用
method对象接住我们正在调用的方法sing(),show()
method==sing(),show();
method.invoke();==>手工调用目标方法
3)InvocationHandler接口
它是实现代理和业务功能的,我们在调用时使用匿名内部实现。
@Test
public void testA(){
Service service=new Service() {
@Override
public void sing() {
System.out.println("哈哈哈哈哈哈哈哈哈");
}
};
service.sing();
}
动态代理代码实现
动态代理类
// 返回动态代理对象
public Object getAgent(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(
// 创建代理对象
Object proxy,
// method就是目标法 sing(),show()
Method method,
// 目标方法的参数
Object[] args) throws Throwable {
//代理功能
System.out.println("预定时间");
// 代理功能
System.out.println("预定场地");
// 主业务功能实现
// target.sing(); 写死了方法的调用 不行
// 此时可能调用 sing show等等任意方法
Object object= method.invoke(target,args);
// 代理功能
System.out.println("结算费用");
return object; //切记这是目标方法的返回值
}
}
);
接口
public interface Service01 {
void sing();
public String show(int age);
}
类
@Override
public String show(int age) {
System.out.println("刘德华的age"+age);
return "liu";
}
@Override
public String show(int age) {
System.out.println("周润发的age"+age);
return "zhou";
}
test
@Test
public void testJDK1(){
ProxyFactory factory=new ProxyFactory(new SuperLiu());
Service01 agent= (Service01) factory.getAgent();
String s=agent.show(15);
System.out.println(s);
}
CGLib动态代理
又称为子类代理,通过动态的在内存中构建子类对象,重写父类的方法进行动态代理功能的增强,
如果目标对象没有实现接口,则只能通过CGLib子类代理来进行功能增强
子类代理是通过字节码框架ASM来实现的.