java之AOP动态代理

一个例子:

package com.zg.spring.proxy;

/**
 * @Auther: zhaoss
 * @Date: 2022/8/2 - 08 - 02 - 23:16
 * @Description: com.zg.spring.proxy
 * @version: 1.0
 */
public interface Calculator {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

package com.zg.spring.proxy;

/**
 * @Auther: zhaoss
 * @Date: 2022/8/2 - 08 - 02 - 23:17
 * @Description: com.zg.spring.proxy
 * @version: 1.0
 */
public class CalculatorImpl implements Calculator {
    @Override
    public int add(int i, int j) {
        System.out.println("日志,方法:add,参数:"+i+","+j);
        int result = i+j;
        System.out.println("计算结果为"+result);
        return result;
    }

    @Override
    public int sub(int i, int j) {
        System.out.println("日志,方法:sub,参数:"+i+","+j);
        int result = i-j;
        System.out.println("计算结果为"+result);
        return result;
    }

    @Override
    public int mul(int i, int j) {
        System.out.println("日志,方法:mul,参数:"+i+","+j);
        int result = i*j;
        System.out.println("计算结果为"+result);
        return result;
    }

    @Override
    public int div(int i, int j) {
        System.out.println("日志,方法:div,参数:"+i+","+j);
        int result = i/j;
        System.out.println("计算结果为"+result);
        return result;
    }
}

package com.zg.spring.proxy;

import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * @Auther: zhaoss
 * @Date: 2022/8/2 - 08 - 02 - 23:19
 * @Description: com.zg.spring.proxy
 * @version: 1.0
 */
public class ProxyFactory {

    public ProxyFactory(Object target) {
        this.target = target;
    }

    private Object target;

    public Object getProxy(){
//        lassLoader loader, 指定加载动态生成的代理类的类加载器
//        Class<?>[] interfaces, 获取目标对象实现的所有接口的class对象数组
//         InvocationHandler h)
        ClassLoader classLoader = this.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        InvocationHandler h = new InvocationHandler() {
            @Override
            //proxy 代理对象,method要执行的方法,args 要执行的方法的参数列表
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("日志,方法: " +method.getName()+", 参数:"+ Arrays.toString(args));
                Object res = method.invoke(target, args);
                System.out.println("日志,方法: " +method.getName()+", 结果:"+ res);
                return res;

            }
        };

        return Proxy.newProxyInstance(classLoader,interfaces,h);
    }


}

package com.zg.test;

import com.zg.spring.proxy.Calculator;
import com.zg.spring.proxy.CalculatorImpl;
import com.zg.spring.proxy.ProxyFactory;
import org.junit.Test;

/**
 * @Auther: zhaoss
 * @Date: 2022/8/2 - 08 - 02 - 23:51
 * @Description: com.zg.test
 * @version: 1.0
 */
public class ProxyTest {

    @Test
    public void testProxy(){
        ProxyFactory proxyFactory = new ProxyFactory(new CalculatorImpl());
        Calculator proxy = (Calculator)proxyFactory.getProxy();
        proxy.add(1,2);
        proxy.mul(3,6);
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zg.sbootT1</groupId>
    <artifactId>sbootT1</artifactId>
    <version>1.0-SNAPSHOT</version>

    <packaging>pom</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.22</version>
        </dependency>
        <!--junit测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!--MyBatis驱动-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.6</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>

        <!--Spring连接Mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.26</version>
        </dependency>

        <!--数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.31</version>
        </dependency>
    </dependencies>


</project>

使用基于注解的AOP:

<?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:context="http://www.springframework.org/schema/context"
       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/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--
        AOP的注意事项:
        切面类和目标类都需要交给IOC容器管理
        切面类必须通过@Aspect注解标识为一个切面
        在Spring的配置文件中设置<aop:aspectj-autoproxy />开启基于注解的AOP
    -->
    <!--扫描-->
    <context:component-scan base-package="com.zg.spring.aop.annotation"></context:component-scan>

    <!--开启基于注解的AOP-->
    <aop:aspectj-autoproxy />

</beans>
package com.zg.spring.aop.annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
@Aspect //切面
public class LoggerAspect {

//    @Before("execution(public int com.zg.spring.aop.annotation.CalculatorImpl.add(int,int))")
//    //@Before("execution(public int com.zg.spring.aop.annotation.CalculatorImpl.*(..))")
//    public void beforeAdviceMethod(){
//        System.out.println("LoggerAspect,前置通知");
//    }


    @Pointcut("execution(* com.zg.spring.aop.annotation.CalculatorImpl.*(..))")
    public void pointCut(){}

    public void beforeAdviceMethod(JoinPoint joinPoint){
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        //获取连接点所对应方法的参数
        Object[] args = joinPoint.getArgs();

        System.out.println("LoggerAspect,方法:"+signature.getName()+",参数:"+ Arrays.toString(args));

    }

    @After("pointCut()")
    public void afterAdviceMethod(JoinPoint joinPoint){
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        System.out.println("LoggerAspect,方法:"+signature.getName()+",执行完毕");
    }


    /**
     * 在返回通知中若要获取目标对象方法的返回值
     * 只需要通过@AfterReturning注解的returning属性
     * 就可以将通知方法的某个参数指定为接收目标对象方法的返回值的参数
     */
    @AfterReturning(value = "pointCut()", returning = "result")
    public void afterReturningAdviceMethod(JoinPoint joinPoint, Object result){
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        System.out.println("LoggerAspect,方法:"+signature.getName()+",结果:"+result);
    }

    /**
     * 在异常通知中若要获取目标对象方法的异常
     * 只需要通过AfterThrowing注解的throwing属性
     * 就可以将通知方法的某个参数指定为接收目标对象方法出现的异常的参数
     */
    @AfterThrowing(value = "pointCut()", throwing = "ex")
    public void afterThrowingAdviceMethod(JoinPoint joinPoint, Throwable ex){
        //获取连接点所对应方法的签名信息
        Signature signature = joinPoint.getSignature();
        System.out.println("LoggerAspect,方法:"+signature.getName()+",异常:"+ex);
    }

    @Around("pointCut()")
    //环绕通知的方法的返回值一定要和目标对象方法的返回值一致
    public Object aroundAdviceMethod(ProceedingJoinPoint joinPoint){
        Object result = null;
        try {
            System.out.println("环绕通知-->前置通知");
            //表示目标对象方法的执行
            result = joinPoint.proceed();
            System.out.println("环绕通知-->返回通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕通知-->异常通知");
        } finally {
            System.out.println("环绕通知-->后置通知");
        }
        return result;
    }
}

package com.zg.spring.aop.annotation;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Order(1)
public class ValidateAspect {
    //@Before("execution(* com.atguigu.spring.aop.annotation.CalculatorImpl.*(..))")
    @Before("com.zg.spring.aop.annotation.LoggerAspect.pointCut()")
    public void beforeMethod(){
        System.out.println("ValidateAspect-->前置通知");
    }
}

package com.zg.spring.test;

import com.zg.spring.aop.annotation.Calculator;
import com.zg.spring.aop.annotation.CalculatorImpl;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AOPTest {

    @Test
    public void testAOPByAnnotation(){
        ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("aop-annotation.xml");

        //使用了AOP 就不能直接访问,必须通过代理对象访问。
//        CalculatorImpl calculator = ioc.getBean(CalculatorImpl.class);
//        calculator.add(3,4);

        Calculator calculator = ioc.getBean(Calculator.class);
        calculator.add(3,4);
    }
}

ssm练习:

properties配置:

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/OneToMany?useUnicode=true&characterEncoding=utf8&autoReconnect=true&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456

mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!--properties,settings,typeAliases, typeHandles, objectFactory,plugins,environment-->
    <!--引入properties 以后就可以用${key}方式访问value-->

    <properties resource="jdbc.properties"/>
    <typeAliases>
        <package name="com.zg.mybatis.project"/>
    </typeAliases>

    <plugins>
        <!--配置分页插件-->
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>

            </dataSource>
        </environment>
    </environments>

    <mappers>
        <!--<mapper resource="mappers/AticleMapper.xml"/>-->
        <!--mapper和mapper.xml放在同一目录下,映射接口DAO和xml不用一个一个映射了-->
        <package name="com.zg.mybatis.mapper"/>
    </mappers>
</configuration>
package com.zg.mybatis.utils;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

/**
 * @Auther: zhaoss
 * @Date: 2022/7/26 - 07 - 26 - 0:47
 * @Description: com.zg.mybatis.utils
 * @version: 1.0
 */
public class SqlSessionUtil {
    public static SqlSession getSqlSession(){
        SqlSession sqlSession =null;
        try {
            //获取核心配置文件输入流
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            //获取SqlSessionFactory对象
            SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
            SqlSessionFactory build = sqlSessionFactoryBuilder.build(is);
            //获取sql会话对象SqlSession
            sqlSession = build.openSession(true);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sqlSession;
    }
}

package com.zg.mybatis.mapper;

import com.zg.mybatis.project.Aticle;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

public interface AticleMapper {

    //int insertAticle();


    Aticle getAticleById();

    Aticle getAticleByTitle(String Title);

    Aticle getAticleByTitleAndMsg(String Title, String Msg);

    Aticle getAticleByTitleAndMsgByMap(Map<String,Object> map);

    List<Aticle> getAllAticle();

    void insertAticle(Aticle aticle);

    //可以在mapper接口上使用@Param 注解,这样@Param("Title") 列名被标注为map的键
    void insertAticleByParam(@Param("Title") String t, @Param("Message") String msg);

    //通过param 定义键值对 @Param("Id") 为键,表名,String id 为传入值
    Aticle getAticleByIdParam(@Param("Id") String id);

    int getCount();

    //根据Id查询所有值,并返回键值对

    List<Map<String, Object>> getAticleByIdToMap();

    //使用Map注解:"id"区分大小写
    @MapKey("id")
    Map<String, Object> getAticleByIdToMap2();
}

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://10.20.91.130/dtd/mybatis-3-mapper.dtd" >

<!--关联DAO-->

<mapper namespace="com.zg.mybatis.mapper.AticleMapper">
<!--mapper接口的全类名要和映射文件的namespace保持一致-->
    <!--mapper接口中的方法的方法名要和映射文件sql中的Id保持一致-->
<!--int insertAticle();-->
    <!--<insert id="insertAticle">-->
        <!--insert into Aticle values(null, "admin","123456")-->
    <!--</insert>-->

    <!--Aticle getAticleById()-->
    <!--result type 设置结果类型 -->
    <!--result map 自定义映射,处理一对一或者多对多-->
    <select id="getAticleById" resultType="com.zg.mybatis.project.Aticle">
        select * from Aticle where id=1
    </select>

    <!--在mybatisconfig里配置完就不用配置resultType了-->
    <!--<typeAliases>-->
        <!--<package name="com.zg.mybatis.project"/>-->
    <!--</typeAliases>-->

    <!--List<Aticle> getAllAticle()-->
    <select id="getAllAticle" resultType="Aticle">
        select * from Aticle
    </select>

    <!--getAticleByTitle(String Title);-->
    <select id="getAticleByTitle" resultType="Aticle">
        <!--select * from Aticle where Title=#{xxxx}-->
        <!--#相当于占位符,不用手动加单引号。 $是sql拼接-->
        select * from Aticle where Title = '${xxxx}'
    </select>

    <!--getAticleByTitleAndMsg(String Title, String Msg)-->
    <select id="getAticleByTitleAndMsg" resultType="Aticle">
        <!--select * from Aticle where Title = #{param1} and Message = #{param2}-->
        select * from Aticle where Title = #{arg0} and Message = #{arg1}
    </select>

    <!--Title 为map中的键,#{Title} 寻找到key所对应的值-->
    <!--Aticle getAticleByTitleAndMsgByMap(Map<String,Object> map);-->
    <select id="getAticleByTitleAndMsgByMap" resultType="Aticle">
        select * from Aticle where Title = #{Title} and Message = #{Message}
    </select>

    <!--void insertAticle(Aticle aticle);-->
    <insert id="insertAticle" >
        insert into Aticle values(null, #{Title}, #{Message})
    </insert>

    <!--void insertAticleByParam(Aticle aticle);-->
    <insert id="insertAticleByParam">
        insert into Aticle values(null, #{Title}, #{Message})
    </insert>

    <!--Aticle getAticleByIdParam(@Param("Id") String id);-->
    <select id="getAticleByIdParam" resultType="Aticle">
        select * from Aticle where Id = #{Id}
    </select>

    <!--int getCount();-->
    <select id="getCount" resultType="int">
        select count(*) from Aticle
    </select>

    <!--Map<String, Object> getAticleByIdToMap();-->
    <select id="getAticleByIdToMap" resultType="map">
        select * from Aticle
    </select>

    <!--Map<String, Object> getAticleByIdToMap2();-->
    <select id="getAticleByIdToMap2" resultType="map">
        select * from Aticle
    </select>
</mapper>

package com.zg.mybatis.project;

public class Aticle {
    public Aticle() {
    }

    public Aticle(Integer id, String title, String message) {
        this.id = id;
        Title = title;
        Message = message;
    }

    private Integer id;
    private  String Title;
    private  String Message;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTitle() {
        return Title;
    }

    public void setTitle(String title) {
        Title = title;
    }

    public String getMessage() {
        return Message;
    }

    public void setMessage(String message) {
        Message = message;
    }



    @Override
    public String toString() {
        return "Aticle{" +
                "id=" + id +
                ", Title='" + Title + '\'' +
                ", Message='" + Message + '\'' +
                '}';
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

潘诺西亚的火山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值