和我一起迎接明天的太阳吧

klaus08

焦虑源于行动的匮乏

2021-07-24 SpringAOP

小小的疑惑,我还是不懂啊。代理模式,切面,切入点



AOP面向切面编程


代理模式

代理模式就是SpringAOP的底层。

代理模式的分类:

  • 静态代理
  • 动态代理

静态代理

角色分析:

  • 抽象角色:一般使用接口或抽象类
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,会做一些附属操作
  • 客户:访问代理对象的人

代理模式的好处:

  • 可以使真实角色的操作更加纯粹
  • 公共业务交给了代理角色,实现类业务的分工
  • 公共业务发生扩展的时候,方便集中管理

缺点:

  • 之歌真实角色就会产生一个代理角色;代码量翻倍

代码分析1

  1. 接口

    package com.klaus.demo01;
    
    //租房
    public interface Rent {
        public void rent();
    }
    
  2. 真实角色

    package com.klaus.demo01;
    
    //房东
    public class Host implements Rent{
        @Override
        public void rent() {
            System.out.println("房东出租房");
        }
    }
    
  3. 代理角色

    package com.klaus.demo01;
    
    public class Proxy implements Rent{
        private Host host;
    
        public Proxy() {
        }
    
        public Proxy(Host host) {
            this.host = host;
        }
    
        @Override
        public void rent() {
            seeHouse();
            host.rent();
            contract();
            charge();
        }
    
        public void seeHouse(){
            System.out.println("中介带你看房子");
        }
    
        public void charge(){
            System.out.println("收中介费");
        }
    
        public void contract(){
            System.out.println("签订租赁合同");
        }
    }
    
  4. 客户类

    package com.klaus.demo01;
    
    public class Client {
        public static void main(String[] args) {
            // 房东要出租房子
            Host host = new Host();
    
            // 代理,中介帮房东租房,但中介一般会多一些附属操作
            Proxy proxy = new Proxy(host);
    
            // 客户不同面对房东,直接找中介租房即可
            proxy.rent();
        }
    }
    

代码分析2

服务类原本只进行增删改查的业务,这时候是不需要代理的。但如果增加需求:每次执行操作时增加日志,直接在真实角色上修改代码不是很妥善,所以用到了代理,代理还是调用原来角色的方法,但是新增了打印日志的方法并且没有改动原代码。

  1. 接口类

    package com.klaus.demo02;
    
    public interface UserService {
        public void add();
        public void delete();
        public void update();
        public void query();
    }
    
  2. 真实角色

    package com.klaus.demo02;
    
    public class UserServiceImpl implements UserService{
        @Override
        public void add() {
            System.out.println("增加了一个对象");
        }
    
        @Override
        public void delete() {
            System.out.println("删除了一个对象");
        }
    
        @Override
        public void update() {
            System.out.println("修改了一个对象");
        }
    
        @Override
        public void query() {
            System.out.println("查询了一个对象");
        }
    }
    
  3. 代理角色

    package com.klaus.demo02;
    
    // 代理模式要有一个真实客户
    public class UserServiceProxy implements UserService{
        UserServiceImpl userService;
    
        public void setUserService(UserServiceImpl userService) {
            this.userService = userService;
        }
    
        @Override
        public void add() {
            userService.add();
            log("add");
        }
    
        @Override
        public void delete() {
            userService.delete();
            log("delete");
        }
    
        @Override
        public void update() {
            userService.update();
            log("update");
        }
    
        @Override
        public void query() {
            userService.query();
            log("query");
        }
    
        // 日志方法
        public void log(String msg){
            System.out.println("使用了" + msg + "方法");
        }
    }
    
  4. 客户类

    package com.klaus.demo02;
    
    public class Client {
        public static void main(String[] args) {
            UserServiceImpl userService = new UserServiceImpl();
    
            UserServiceProxy userServiceProxy = new UserServiceProxy();
            userServiceProxy.setUserService(userService);
            userServiceProxy.delete();
        }
    }
    

动态代理(on 反射)

  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不像静态类要自己写
  • 动态代理分两类:
    1. 基于接口的动态代理 — JDK动态代理
    2. 基于类的动态代理 ----- cglib
    3. 还有java 字节码:javasist

ProxyInvocationHandler 和 Proxy


AOP实现

一、使用Spring的API

  1. UserService.java

    package com.klaus.service;
    
    public interface UserService {
        public void add();
        public void delete();
        public void update();
        public void query();
    }
    
  2. UserServiceImpl.java

    package com.klaus.service;
    
    public class UserServiceImpl implements UserService{
        @Override
        public void add() {
            System.out.println("add user");
        }
    
        @Override
        public void delete() {
            System.out.println("delete user");
        }
    
        @Override
        public void update() {
            System.out.println("update user");
        }
    
        @Override
        public void query() {
            System.out.println("query user");
        }
    }
    
  3. Log.java

    package com.klaus.log;
    
    import org.springframework.aop.MethodBeforeAdvice;
    
    import java.lang.reflect.Method;
    
    public class Log implements MethodBeforeAdvice {
        // method: 要执行对象的方法
        // args: 参数
        // o: equals target
        @Override
        public void before(Method method, Object[] args, Object o) {
            System.out.println(o.getClass().getName()+ "的" + method.getName() + "被执行");
        }
    }
    
  4. AfterLog.java

    package com.klaus.log;
    
    import org.springframework.aop.AfterAdvice;
    import org.springframework.aop.AfterReturningAdvice;
    import java.lang.reflect.Method;
    
    public class AfterLog implements AfterReturningAdvice {
        @Override
        public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
            System.out.println("执行了" + target.getClass().getName()+ "的" + method.getName() +
                    "方法,返回结果为" + returnValue);
        }
    }
    
  5. applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop
            http://www.springframework.org/schema/aop/spring-aop.xsd">
    
        <bean id="userService" class="com.klaus.service.UserServiceImpl" />
        <bean id="log" class="com.klaus.log.Log"/>
        <bean id="afterLog" class="com.klaus.log.AfterLog"/>
    
        <!-- 配置AOP -->
        <aop:config>
            <!-- 切入点 -->
            <!--execution()里 返回类型 函数范围 参数   -->
            <aop:pointcut id="pointcut" expression="execution(* com.klaus.service.UserServiceImpl.*(..))"/>
    
            <!-- 执行环绕增强 -->
            <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
            <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
        </aop:config>
    </beans>
    
  6. MyTest.java

    import com.klaus.service.UserService;
    import com.klaus.service.UserServiceImpl;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MyTest {
        public static void main(String[] args) {
            ApplicationContext context =
                    new ClassPathXmlApplicationContext("applicationContext.xml");
            UserService userService = (UserService) context.getBean("userService");
    
            userService.add();
        }
    }
    
  7. 执行结果

    com.klaus.service.UserServiceImpl的add被执行
    add user
    执行了com.klaus.service.UserServiceImpl的add方法,返回结果为null
    

二、自定义实现AOP

三、使用注解实现

posted @ 2021-07-24 17:27  klaus08  阅读(33)  评论(0编辑  收藏  举报