什么是代理模式?
作用:为对象提供一种代理控制对对象的访问
代理模式的好处?
不想或者是不能直接引用访问另一个对象 代理对象可以在目标和使用者之间起到中介作用
代理模式涉及的角色
抽象角色 声明真实对象和代理对象共同的接口
代理角色 代理角色对象的内部都持有真实的对象的引用 操作真实的对象
真实角色 代理角色所代表的角色
调用方法通过经纪人访问明星
静态代理
一般在编码时就确定了代理和被代理的对象关系 如果运行时才确定的代理行为 静态代理不合适
静态代理的弊端
1.在运行前就需要手动创建代理类 代理类较多时比较麻烦
2.代理类和被代理类必须实现共同的接口 接口变动 代理类和被代理类需要修改代码
动态代理
public class Test {
public static void main(String[] args) {
// Star star=new Star("wangbaoqiang");
// Angent angent=new Angent(star);
// angent.movieShow(300000000);
// angent.tvShow(2000000000);
Star star=new Star("wangbaoqiang");
ProxyHandler handler=new ProxyHandler(star);
IMovieStar angent=(IMovieStar) handler.getProxy();//通过动态代理类生成动态代理的对象
angent.movieShow(30000000);
angent.tvShow(100);
}
}
public class ProxyHandler implements InvocationHandler{
//持有被代理对象的引用
private Object target;
public ProxyHandler(Object target){
this.target=target;
}
/**
* 方法的拦截 可以根据method的名称创建类信息进行处理
* Method method, 拦截的方法
* Object[] args 方法对应的参数
*
* x.class().method("tvShow",int.class)
* method.invoke(x,1000000);
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName=method.getName();//获取拦截处理的方法的名称
if(methodName.equals("movieShow") ||methodName.equals("tvShow")){
if(args[0] instanceof Integer && ((Integer)args[0])<10000000){
System.out.println(args[0]+"钱太少!找xxx去吧");
return null;
}
}
Object result=method.invoke(target,args);
return result;
}
//Proxy.newProxyInstance() 生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
/*
*
* public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler i){
* }
* ClassLoader loader, 被代理类的加载器 用来创建代理类
* Class<?>[] interfaces, 被代理类实现的接口 创建的代理类都实现接口
* InvocationHandler i 关键 它的类中具有唯一的invoke方法 代理类进行拦截操作的函数
*/
}
注解:
标注解释的标记 加了注解的程序存在标记 通过反射获取字节码文件对象读取类中的成员(构造函数 变量 函数 类成员上标记)
标记可以添加在包 类 变量 方法
@Override 重写父类或者父接口中的方法
@Deprecated 类或者成员过时
@SuppressWarnings 排除警告
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//当前的注解可以标记在成员变量 对象 属性
public @interface AnnotationName {//@AnnotationName()
//声明注解的属性
String value() default “Hello”; //value=”qq”
}
public class TestAnnotation {
@AnnotationName("zhangsan")// value="qq"
public String info;//使用注解的形式info赋值
public static void main(String[] args) {
TestAnnotation ta=new TestAnnotation();
parserAnnotation(ta);
System.out.println(ta.info);// qq
}
/**
* 定义解释注解的方法
* @param ta
*/
public static void parserAnnotation(TestAnnotation ta){
try {
//根据类的对象获取类的字节码文件对象
Class clazz=ta.getClass();
//根据字节码文件对象指定类中的变量的名称获取变量
Field field=clazz.getField("info");
//获取info字段上的注解
Annotation[] annotations=field.getDeclaredAnnotations();
//info字段上存在注解
if(annotations!=null && annotations.length!=0){
Annotation an=annotations[0];//获取属性中的第一个注解
//获取注解的名称
String name=an.annotationType().getName();
System.out.println("注解的名称--------"+name);
if(name.equals(AnnotationName.class.getName())){
AnnotationName anName=(AnnotationName) an;
//set(表示给那个对象的属性赋值,表示赋值的内容) 将注解的value的值赋值给ta对象的info
field.set(ta, anName.value());//new TestAnnotation().info="qq"
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
注解以@interface关键字来定义 声明元注解(注解的注解 标示注解的生命周期 使用位置等)
@Retention 元注解 表示需要在什么级别保存该注解信息(生命周期)
RetentionPolicy.RUNTIME 表示虚拟机运行时保留注解
RetentionPolicy.SOURCE 表示停留在java源文件
RetentionPolicy.CLASS 停留在class文件中 默认
@Target元注解 表示该注解用于什么地方(类 方法 变量)
@Documented 元注解 将注解包含在javadoc中
@Inherited 元注解 允许子类继承父类中的注解
定义注解的步骤:
1.以@interface创建注解文件
2.声明元注解@Retention和@Target
3.声明注解的属性和默认值
4.使用解析注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//当前的注解可以标记在成员变量 对象 属性
public @interface AnnotationName {//@AnnotationName()
//声明注解的属性
String value() default “Hello”;
}
public class AnnotationName{
String value=”Hello”;
}