代理:对类的包装,使其的方法功能更加强大.
目标对象:需要被代理的对象;
代理对象:目标对象的代理者.
静态代理
1.静态代理by接口
- 做3件事
1 代理对象实现于目标对象的接口
2 将目标对象注入到代理对象中
3 代理对象在方法中,对目标对象进行包装
代理对象的接口
public interface IUser {
public void dowork(String name);
public void dowork2(Integer age);
}
目标对象
public class User implements IUser{
public void dowork(String name) {
System.out.println("hi!"+name);
}
public void dowork2(Integer age) {
System.out.println("you age "+age);
}
}
代理对象
public class MyProxy implements IUser{
private User user;
public MyProxy (User user){
this.user=User
}
//对方法包装
public void dowork(String name) {
System.out.println("开始");
user.dowork(name);
System.out.println("结束");
}
//对方法包装
public void dowork2(Integer age) {
Integer newAge=age+1;
user.dowork(newAge);
}
}
使用方式
- 获取目标对象
- 通过目标对象创建代理对象
- 调用代理对象的方法
public void test1(){
User user = new User();
IUser Proxy=new MyProxy(user); //用接口接收
Proxy.dowork(XXX);
}
2.静态代理by继承
- 做2件事
1 代理对象继承于目标对象的接口
2 覆盖需要包装的方法,方法内部还是调用super.方法(),多了一些别的内容;
public class MyProxy extends User{
//对方法包装
public void dowork(String name) {
System.out.println("开始");
Super.dowork(name); //使用目标对象的方法
System.out.println("结束");
}
//对方法包装
public void dowork2(Integer age) {
Integer newAge=age+1;
Super.dowork(newAge);
}
}
使用方式
- 直接获取代理对象进行操作即可.
User user = new MyProxy
3.静态的缺点
- 每一个目标对象需要一个静态代理对象.代理对象不能通用,很麻烦.
- 解决方法:动态代理,相对静态代理,可以做出一个通用的代理对象.
Spring的动态代理
可以针对某一个功能,做出一个对不同目标对象,进行相同包装的代理类.
比如,对所有类的所有方法,都要计算出其方法运行完的时间.
静态代理需要一个类写一次代理类;动态代理写一个即可,然后代理对象通过Spring方法返回.
1.代理功能声明的类 实现于InvocationHandler
作用:可以让各种类使用从而获得代理对象
1. 创建通用的代理类,实现接口InvocationHandler,并覆盖方法invoke;
2. 创建字段,private Object obj
代表目标对象,通过构造器复制;(反射方式调用方法需要传入目标对象)
3. 完成覆盖方法,实现代理.invoke(自己本身对象, 目标对象的方法,方法中的参数)
public class MyProxy implements InvocationHandler{
//引入目标对象
private Object obj;
public MyProxy(Object obj) {this.obj=obj;}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long start = System.currentTimeMillis();
Object ret=method.invoke(obj, args);//反射方式执行方法
long over = System.currentTimeMillis();
System.out.println(start-over);
return ret;
}
}
2.动态代理by接口
调用Spring的生成代理对象的方法
代理对象=(接口强转)Proxy.newProxyInstance(3个形参);因为返回的接口对象是实现于目标对象接口的,与目标对象是兄弟关系,要用接口接收;
- 目标对象的类加载器 ;目标对象.getClass().getClassLoader()
- new Class[]{接口的Class对象};//要去实现接口
- new MyProxy(目标对象);
@Test
public void dowork(){
User user=new User();
IUser userProxy = (IUser)Proxy.newProxyInstance(user.getClass().getClassLoader()
,new Class[]{IUser.class}
,new MyProxy(user)); //返回的就是代理对象,1.必须接口接收,2.接口强转
}
3.动态代理by继承
- 创建一个Spring包的增强器:Enhancer en = new Enhancer();
- 增强器器注入三个属性:
- 目标对象的类加载器,
- 目标对象的类对象,要去继承这个类
- new MyProxy(目标对象);
- 增强器生成代理对象
@Test
public void dowork2(){
Enhancer en = new Enhancer();
en.setClassLoader(user.getClass().getClassLoader());
en.setSuperclass(user.getClass());
en.setCallback(new MyProxy(user));
User userProxy =(User)en.create();//返回的可以用目标对象的类接收,也可以用接口接收,强转一样
}
4.Spring动态代理的缺点
- 写一个InvocationHandler实现类,完成了代理功能对不同目标对象通用,
- 但是为了获得代理对象,都需要调用生产代理对象方法,很麻烦.
- 解决方法:Spring AOP功能,在xml中声明即可,以后目标对象对象无需额外操作,即可当代理对象使用———–Spring帮助java完成面向切面编程.