静态代理
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需要修改,可以通过代理的方式来扩展该方法
举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接联系明星,而是联系明星的经纪人,来达到同样的目的.明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决.这就是代理思想在现实中的一个例子。
代理模式的关键点是:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象
静态代理角色分析
抽象角色 : 一般使用接口或者抽象类来实现
真实角色 : 被代理的角色
代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
客户 : 使用代理角色来进行一些操作 .
代码实现:
写一个接口
public interface Singer {
//定义一个唱歌的方法
public void sing();
}
定义男歌手
public class MaleSinger implements Singer {
@Override
public void sing() {
System.out.println("歌手开始唱歌");
}
}
定义经纪人
public class Agent implements Singer {
private Singer singer;
public Agent(Singer singer) {
this.singer = singer;
}
@Override
public void sing() {
System.out.println("节目组找过来!需要演出,谈好演出费用。。。。。");
singer.sing();
System.out.println("结算费用,下一次合作预约。。。。。。");
}
}
Client . java 即客户
public class Client {
public static void main(String[] args) {
Singer singer = new zhouijelun();
Singer maleSinger = new Agent(singer);
maleSinger.sing();
}
}
静态代理总结:
1.可以做到在不修改目标对象的功能前提下,对目标功能扩展.
2.缺点:
因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.
如何解决静态代理中的缺点呢?答案是可以使用动态代理方式
动态代理
- 动态代理的角色和静态代理的一样 .
- 动态代理的代理类是动态生成的 . 静态代理的代理类是我们写的
- 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
- 基于接口的动态代理----JDK动态代理
- 基于类的动态代理–cglib
动态代理就是当有大量的类需要执行一些共同代码时,我们自己写太麻烦,那能不能直接使用java代
码,自动生成一个类帮助我们批量的增强某些方法。
(1)JDK原生的动态代理
JDK动态代理是通过java.lang.reflect.Proxy类来实现的,我们可以调用Proxy类的newProxyInstance()方法来创建代理对象。对于使用业务接口的类,Spring默认会使用JDK动态代理来实现AOP。
代码实现:
创建UserDao接口,并编写添加方法和删除方法。
public interface UserDao {
public void addUser();
public void deleteUser();
}
创建userDao的实现类。
public class UserDaoImpl implements UserDao{
@Override
public void addUser() {
System.out.println("添加用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
}
创建切面类,并定义模拟检查权限方法,和模拟记录日志方法。
public class MyAspect {
public void check_Permissions(){
System.out.println("模拟检查权限");
}
public void log(){
System.out.println("模拟记录日志");
}
}
创建代理类,该类需要实现InvocationHandler接口
/**
* JDK代理类
*/
public class JdkProxy implements InvocationHandler {
//声明目标类接口。
private UserDao userDao;
//创建代理方法
public Object createProxy(UserDao o){
this.userDao = o;
//类加载器
ClassLoader classLoader = JdkProxy.class.getClassLoader();
//被代理对象实现的所有接口
Class<?>[] interfaces = userDao.getClass().getInterfaces();
//使用代理类,进行增强,返回的是代理后的对象
return Proxy.newProxyInstance(classLoader,interfaces,this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//声明切面
MyAspect myAspect = new MyAspect();
//前增强
myAspect.check_Permissions();
//在目标类上调用方法,并传入参数
Object obj = method.invoke(userDao, args);
//后增强
myAspect.log();
return obj;
}
}
JDKProxy实现了InvocationHandler接口,并实现了接口中的invoke()方法,所有动态代理类所调用的方法都会讲给该方法处理。在创建的代理方法createProxy()中,使用了Proxy类的newProxyInstance()方法来创建代理对象。newProxyInstance()方法中包含3个参数,其中第一个参数是当前类的类加载器,第2个参数表示的是被代理对象实现的所有接口,第三个参数,this代表的就是代理类JdkProxy本身。在invoke()方法中,目标类方法执行的前后会分别执行切面类中的check_Permissions()方法和log()方法。
创建测试类:
public class JdkTest {
public static void main(String[] args) {
//创建代理对象
JdkProxy jdkProxy = new JdkProxy();
//创建目标对象
UserDaoImpl userDao = new UserDaoImpl();
//从代理对象中获取增强后的目标对象
UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao);
//执行方法
userDao1.addUser();
userDao1.deleteUser();
}
}
执行结果: