spring 03 AOP

0. 代理模式 (AOP的原理)

代理模式

Rent:

//抽象角色:租房
public interface Rent {
   public void rent();
}

Host:

//真实角色: 房东,房东要出租房子
public class Host implements Rent{
   public void rent() {
       System.out.println("房屋出租");
  }
}

Proxy:

//代理角色:中介
public class Proxy implements Rent {

   private Host host;
   public Proxy() { }
   public Proxy(Host host) {
       this.host = host;
  }

   //租房
   public void rent(){
       seeHouse();
       host.rent();
       fare();
  }
   //看房
   public void seeHouse(){
       System.out.println("带房客看房");
  }
   //收中介费
   public void fare(){
       System.out.println("收中介费");
  }
}

Client:

//客户类,一般客户都会去找代理!
public class Client {
   public static void main(String[] args) {
       //房东要租房
       Host host = new Host();
       //中介帮助房东
       Proxy proxy = new Proxy(host);

       //你去找中介!
       proxy.rent();
  }
}

分析:在这个过程中,你直接接触的就是中介,就如同现实生活中的样子,你看不到房东,但是你依旧租到了房东的房子通过代理,这就是所谓的代理模式。

静态代理的好处:

  • 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
  • 公共的业务由代理来完成 . 实现了业务的分工 ,
  • 公共业务发生扩展时变得更加集中和方便 .

缺点 :

  • 类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .

1. 代理模式

若有userservice 实现增删查改:

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

public class UserServiceImp implements UserService{
    public void add() {
        System.out.println("Add User");
    }

    public void delete() {
        System.out.println("Delete User");
    }

    public void update() {
        System.out.println("Update User");
    }

    public void query() {
        System.out.println("Query User");
    }
}

若是在 add、delete、update、query 添加日志:输出“data operation”.在每个语言中就重复的相同语句。一个好的方法是将这些额外的操作方法“代理中去”。UserService 专注于相应的操作,其余日志等操作交给Proxy来完成!
UserServiceProxy:

public class UserServiceProxy implements UserService{

    //UserService 就是被代理的对象
    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void add() {
        log("add");
        userService.add();
    }

    public void delete() {
        log("delete");
        userService.delete();
    }


    public void update() {
        log("update");
        userService.update();
    }

    public void query() {
        log("query");
        userService.query();
    }

    public void log(String msg){
        System.out.println("Add "+ msg +" operation");
    }
}

其中 UserServiceImp 被USerServiceImp代理了。

  • 修改原有代码是大忌。

    优点:
  • 使真实的操作专注,将公告的操作交给代理
  • 可以方便拓展,原有代码不变
缺点:
  1. 一个角色一个代理,若是角色过多,代理也就过多了。
开发一般流程

spring 03 AOP_第1张图片

2. AOP

AOP(面向切面编程):通过预编译方
式和运行期动态代理实现程序功能的统一维护的一种技术。

spring 03 AOP_第2张图片

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....
  • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。(比如Logger类)
  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。(Logger类中的一个方法:log())
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。(代理类)
  • 切入点(PointCut):切面通知 执行的 “地点”的定义。(在哪里执行)
  • 连接点(JointPoint):与切入点匹配的执行点。(在哪里执行)

spring 03 AOP_第3张图片
spring 03 AOP_第4张图片
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
spring 03 AOP_第5张图片

2.2 AOP配置(基于Spring的接口实现)

想要使用AOP织入,需要在pox.xml导入一个依赖包!


     org.springframework
     spring-aspects
     5.3.10

代码:(上面的案例)

  • Spring的API接口
    UserService 和 UserServiceImp代码如上。
    定义Log 和 AfterLog
// 定义Log 继承MethodBeforeAdvice 接口
//
public class Log implements MethodBeforeAdvice {
    // method: 要执行目标函数的方法
    //object :参数
    // targert: 目标对象。(被代理的)
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println( target.getClass().getName() +"的" + method.getName() +" 被执行了");
    }
}

// 返回结果
public class AfterLog implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName() +" 方法; 返回结果为 :" + returnValue);
    }
}

在Bean.xml 中




    
    
    

    
        
        
        
        
    


Test:

    public static void main(String[] args) {
        ApplicationContext context =  new ClassPathXmlApplicationContext("applicationContext.xml");
        // 动态代理的是接口, 要使用 UserService ,而不是 UserServiceImp
        UserService userService = (UserService) context.getBean("userService");
        userService.add();
    }
  1. 配置
  2. 就是切入点(定义的),也就是在哪里插入;expression就是要代理的方法;
  3. 通知,也就是自己定义的,然后引用切入点,pointcut-ref=“pointcut”
2.2 定义类实现AOP

自定义切面

public class DiyPointcut {
    public void methodeBefore(){
        System.out.println("method before");
    }

    public void methodAfter(){
        System.out.println("method before");
    }
}

在Beans.xml 中

    
    
    
  
    
        
        
           
            
            
            
            
        
    
  • 其中, 切面,对象为类(我么自定义的),通过 ref 引用
  • 切入点
  • 在方法之前执行;对比上面的Log,这个方法放在Log里面类中执行的
  • 同样的道理

Test:

    public static void main(String[] args) {
        ApplicationContext context =  new ClassPathXmlApplicationContext("applicationContext.xml");
        // 动态代理的是接口, 要使用 UserService ,而不是 UserServiceImp
        UserService userService = (UserService) context.getBean("userService");
        userService.add();
    }
2.3 注解实现AOP
@Aspect
public class AnnotationPoint {

    @Before("execution(* com.service.UserServiceImp.*(..))")
    public void before(){
        System.out.println("opeation before");
    }
}
  • @Aspect 使用注解设置切面(对上小姐的
  • @Before 对应 (通知:advice),里面的参数对应切入点(pointcut)。

使用注解在 Beans.xml, 需要开启注解:

  
  

你可能感兴趣的:(springjava)