动态代理的两个使用方式(手动实现+SpringAOP实现)-Demo

一、手动实现

1、具体代码

package com.xch.proxy;

/**
 * 具体业务接口
 *
 * @author XuChenghe
 * @date 2023/8/18 15:09
 */
public interface Star {
    
    /**
     * 唱歌方法
     *
     * @param name
     * @return
     */
    String sing(String name);
    
    /**
     * 跳舞方法
     */
    void dance();
    
}
package com.xch.proxy;

/**
 * 具体业务实现类
 *
 * @author XuChenghe
 * @date 2023/8/18 15:06
 */
public class BigStar implements Star {
    private String userName;
    
    public BigStar(String userName) {
        this.userName = userName;
    }
    
    /**
     * {@inheritDoc}
     */
    public String sing(String songName) {
        System.out.println(this.userName + "正在唱:" + songName);
        return "谢谢!谢谢!";
    }
    
    /**
     * {@inheritDoc}
     */
    public void dance() {
        System.out.println(this.userName + "正在优美的跳舞~~");
    }
    
}
package com.xch.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理的工具类(产生代理的)
 * -手动实现原生动态代理
 *
 * @author XuChenghe
 * @date 2023/8/18 15:11
 */
public class ProxyUtil {
    
    public static Star createProxy(BigStar bigStar) {
        // 参数1:ClassLoader用于指定一个类加载器
        // 参数2:指定生成的代理有哪些方法
        // 参数3:用来指定生成的代理对象要干什么事情(动态代理的核心)
        Star starProxy = (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),
                new Class[]{Star.class}, new InvocationHandler() {
                    // 回调方法
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 动态代理要做的事情,会在这里写代码
                        if ("sing".equals(method.getName())) {
                            System.out.println("准备话筒,收钱20万");
                        } else if ("dance".equals(method.getName())) {
                            System.out.println("准备场地,收钱100万");
                        }
                        return method.invoke(bigStar, args);
                    }
                }
        );
        return starProxy;
    }
    
}
package com.xch.proxy;

/**
 * 运行启动测试类
 *
 * @author XuChenghe
 * @date 2023/8/18 15:21
 */
public class LaunchTest {
    
    public static void main(String[] args) {
        Star starProxy = ProxyUtil.createProxy(new BigStar("杨超越"));
        
        String result = starProxy.sing("好日子");
        System.out.println(result);
        
        starProxy.dance();
    }
    
}

二、SpringAOP实现

1、pom文件依赖



    org.springframework.boot
    spring-boot-starter-aop



    org.springframework
    spring-tx

2、具体代码

package com.xch.proxy_product;

/**
 * 具体业务接口
 *
 * @author XuChenghe
 * @date 2023/8/18 15:09
 */
public interface Star {
    
    /**
     * 实际生产中使用的代理调用
     *
     * @param name
     * @return
     */
    String proxySing(String name);
    
    /**
     * 实际生产中使用的代理调用
     */
    void proxyDance();
    
}
package com.xch.proxy_product;

import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 具体业务实现类
 *
 * @author XuChenghe
 * @date 2023/8/18 15:06
 */
@Service
public class BigStar implements Star {
    
    /**
     * 唱歌方法
     *
     * @param songName
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public String sing(String songName) {
        System.out.println("杨超越正在唱:" + songName);
        return "谢谢!谢谢!";
    }
    
    /**
     * 跳舞方法
     */
    @Transactional(rollbackFor = Exception.class)
    public void dance() {
        System.out.println("杨超越正在优美的跳舞~~");
    }
    
    /**
     * {@inheritDoc}
     */
    @Transactional(rollbackFor = Exception.class)
    public String proxySing(String songName) {
        System.out.println("准备话筒,收钱20万");
        return getCurrentProxy().sing("好日子");
    }
    
    /**
     * {@inheritDoc}
     */
    @Transactional(rollbackFor = Exception.class)
    public void proxyDance() {
        System.out.println("准备场地,收钱100万");
        getCurrentProxy().dance();
    }
    
    /**
     * 获取当前类的代理
     *
     * @return 当前类的代理
     */
    private static BigStar getCurrentProxy() {
        return (BigStar) AopContext.currentProxy();
    }
    
}
package com.xch.proxy_product;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * 通用业务的切面类
 *
 * @author XuChenghe
 * @date 2023/8/20 8:55
 */
@Aspect // 声明该类的作用:切面类
@Component // 等价于@Configuration:交由Spring的IOC容器管理
public class BigStarAspect {
    
    /**
     * 定义公共切入点
     * -假设proxy_product是service业务层包
     * -则通过以下表达式匹配该业务包下的所有子孙类的所有public修饰的方法
     *
     * 另外,配置的切入表达式必须是符合public修饰的方法
     * 因为,Spring事务即AOP的底层通过动态代理生成代理调用该方法时,
     * 会判断方法只能是public修饰的Modifier.isPublic(method.getModifiers())
     */
    @Pointcut("execution(public * com.xch.proxy_product..*(..))")
    public void myPointcut() {
        // 公共切入点
    }
    
    /**
     * 配置切面方法(环绕通知):方法增强
     *
     * @param pjp 连接点:当前切入方法的信息
     * @return 方法执行的返回结果
     * @throws Throwable 方法执行时抛出的异常
     */
    @Around("myPointcut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("=====环绕通知(开始)=====");
        // 前置增强代码
        Object proceed = pjp.proceed();
        // 后置/返回增强代码
        // 最终增强代码
        // 抛出异常后增强代码
        System.out.println("=====环绕通知(结束)=====");
        return proceed;
    }
}
package com.xch;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * 启用Spring的动态代理,默认使用JDK动态代理(由proxyTargetClass控制)
 */
@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true)
public class SubDynamicProxyApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(SubDynamicProxyApplication.class, args);
    }
    
}
package com.xch.proxy_product;

import org.junit.jupiter.api.Test;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

/**
 * 运行启动测试类
 *
 * @author XuChenghe
 * @date 2023/8/18 15:21
 */
@SpringBootTest
public class LaunchTest {
    
    @Autowired
    private Star star;
    
    @Test
    public void launch() {
        String result = star.proxySing("好日子");
        System.out.println(result);
    
        System.out.println();
        star.proxyDance();
    
        // 判断该注入类是否代理类
        // -Spring的IOC容器中默认都是原生对象
        // -只有配置了AOP增强的对象才是代理对象
        System.out.println(AopUtils.isAopProxy(star));
    }
    
}

你可能感兴趣的:(基础知识,java,代理模式)