spring AOP 静态代理和动态代理

来源:互联网 发布:海岛奇兵升船数据 编辑:程序博客网 时间:2024/06/05 15:01

原文:点击打开链接


spring AOP:称为spring的面向切面编程。
既然是切面,自然是要加入一些其他的与逻辑无关的功能,如身份校验,日志打印等。但是,如果代码中加入了这些功能,有新需求时又需要全部更改,这无疑很麻烦,于是就有了代理类的出现:静态代理,动态代理。
1.UserService
public interface UserService {
  public void addUser();
  public void deleteUser();
}
 
2.UserServiceImpl
public class UserServiceImpl implements UserService {
 public void addUser() {
      System.out.println("add user");
 }
 public void deleteUser() {
  System.out.println("delete user");
 }
}
 
那么这个时候要在添加和删除之前添加开始打印的日志,并且完成时添加结束打印的日志。
先来看静态代理:
3.UserProxyImpl
public class UserProxyImpl implements UserService{
    private UserServiceImpl userServiceImpl;
 
    public UserProxyImpl(UserServiceImpl userServiceImpl){
     this.userServiceImpl = userServiceImpl;
    }
 @Override
 public void deleteUser() {
    System.out.println("begin delete user");
       userServiceImpl.deleteUser(); 
       System.out.println("end delete user");
 }
 @Override
 public void addUser() {
    System.out.println("begin add user");
    userServiceImpl.addUser(); 
    System.out.println("end add user");
 }
}
 
 
4.TestProxy
public class TestProxy {
    public static void main(String[] args) {
     UserProxyImpl userProxyImpl = new UserProxyImpl(new UserServiceImpl());
     userProxyImpl.addUser();
 }
}
这样即是使用静态代理,虽然打印日志时,不会改变userServiceImpl里面的内容,但是如果添加需求时,仍然要改变userProxyImpl里面的内容,如果方法有上百个,可知工作量是多么的大,太麻烦了。动态代理可以解决这个问题。
 
动态代理:动态代理常用的,主要有jdk的动态代理,cglib的动态代理
区别:jdk的动态代理一定是用于接口,但是cglib是用于类,有没有接口都实现。
先来看jdk的动态代理:
1.UserService接口
 同上
2.UserServiceImpl实现类
 同上
不再需要UserProxyImpl了,而是将打印日志的语句单独的抽象出来放到一个类中,该类实现InvocationHandler接口
3.addLog
public class addLog implements InvocationHandler{
  private Object taObject;  
      
 public Object createProcy(Object objectTarget){
  this.taObject=objectTarget;
  return Proxy.newProxyInstance(taObject.getClass().getClassLoader(),
                          taObject.getClass().getInterfaces(),
                          this);
 }
 public Object invoke(Object proxy, Method method, Object[] args)
   throws Throwable {
  beforeLog();
    Object object = method.invoke(taObject, args);
  afterLog();
  return object;
 }
 
 private void beforeLog(){
  System.out.println("begin ooperation");
 }
 private void afterLog(){
  System.out.println("after operation");
 }
}
 解释一下这个addLog类,该类有四个方法,分别为createProxy,invoke,beforeLog,afterLog,其中invoke方法为实现InvocationHander时重载的方法。
 
creteProxy方法:需要的参数为需要代理的类,Proxy.newProxyInstance将返回一个代理类,参数分别为:
  taObject.getClass().getClassLoader():得到被代理类的加载器
 taObject.getClass().getInterfaces():得到被代理类的所有接口
 this:将得到该InvocationHandler的子类
 
产生的代理类,最终将调用invoke方法中的method.invoke来执行真正的被代理类,不过开始和结束都有打印日志的方法,所以invoke方法里面有个Proxy参数,就是用来调用方法的代理类。
 
4.TestProxy
public class TestProxy {
    public static void main(String[] args) {
     CheckSecurity checkSecurity = new CheckSecurity();
     UserService userService = (UserService)checkSecurity.createProcy(new UserServiceImpl());
  userService.deleteUser();
 }
}
可以看到userService为jdk的代理类
 
如果不实现userService接口,UserServiceImpl中自己拥有addUser,deleteUser方法,那么同样的addLog类,生成的代理类将为cglib代理类。

原创粉丝点击