【JavaEE案例】Spring AOP

【案例介绍】

(1)JDK动态代理

(2)CGLib动态代理

 

(3)基于XML的AOP实现

 

(4)基于注解的AOP实现

【案例实现】

  • 创建项目
  • 引入相关依赖:在pom.xml文件中加载依赖包
<?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.itheima</groupId>
    <artifactId>userManager</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.16</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.3.16</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.7</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.7</version>
        </dependency>
    </dependencies>

</project>

1.0 在src/main/java/com.itheima目录下创建demo01包。

1.1 创建接口UserDao.java,在UserDao接口中编写添加和删除的方法。

package com.itheima.demo01;

public interface UserDao {
    public void addUser();
    public void deleteUser();
}

1.2  创建接口UserDao的实现类UserDaoImpl.java,分别实现接口中的方法。

package com.itheima.demo01;
//目标类
public class UserDaoImpl implements UserDao{
    public void addUser() {
        System.out.println("添加用户");
    }
    public void deleteUser() {
        System.out.println("删除用户");
    }
}

1.3 创建切面类MyAspect.java,在该类中定义一个模拟权限检查的方法和一个模拟日志记录的方法,这两个方法就是切面中的通知。 

package com.itheima.demo01;
//切面类:存在多个通知Advice(增强的方法)
public class MyAspect {
    public void check_Permission() {
        System.out.println("模拟检查权限...");
    }

    public void log() {
        System.out.println("模拟记录日志...");
    }
}

1.4 创建代理类MyProxy.java,该类需要实现InvocationHandler接口设置代理类的调用处理程序。

package com.itheima.demo01;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//JDK代理类
public class MyProxy implements InvocationHandler {
    //声明目标类接口
    private UserDao userDao;
    //创建代理方法
    public Object createProxy(UserDao userDao) {
        this.userDao = userDao;
        //1.类加载器
        ClassLoader classLoader = MyProxy.class.getClassLoader();
        //2.被代理对象实现的所有接口
        Class[] classes = userDao.getClass().getInterfaces();
        //3.使用代理类进行增强,返回的是代理对象
        return Proxy.newProxyInstance(classLoader, classes, this);
    }
    /*
    * 所有动态代理类的方法调用,都会交由invoke()方法去处理
    * proxy被代理的对象
    * method将要被执行的方法信息(放射)
    * args执行方法时需要执行的参数
    */

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //创建切面对象
        MyAspect myAspect = new MyAspect();
        //前增强
        myAspect.check_Permission();
        //在目标类上调用方法,并传入参数
        Object obj = method.invoke(userDao, args);
        //后增强
        myAspect.log();
        return  obj;
    }
}

1.5 创建测试类demo01_JDKTest.java

package com.itheima;


import com.itheima.demo01.MyProxy;
import com.itheima.demo01.UserDao;
import com.itheima.demo01.UserDaoImpl;

public class JDKTest {
    public static void main(String[] args){
        //创建代理对象
        MyProxy jdkProxy = new MyProxy();
        //创建目标对象
        UserDao userDao = new UserDaoImpl();
        //从代理对象中获取增强后的目标对象
        UserDao userDao1 = (UserDao) jdkProxy.createProxy(userDao);
        //执行方法
        userDao1.addUser();
        userDao1.deleteUser();
    }
}

2.0 在src/main/java/com.itheima目录下创建demo02包。

2.1 创建目标类UserDao.java,在该类中编写添加用户和删除用户的方法。

package com.itheima.demo02;
//目标类
public class UserDao {
    public void addUser() {
        System.out.println("添加用户");
    }

    public void deleteUser() {
        System.out.println("删除用户");
    }
}

2.2 创建代理类CglibProxy.java,该类需要实现MethodInterceptor接口设置代理类的调用处理程序。 

package com.itheima.demo02;

import java.lang.reflect.Method;
import com.itheima.demo01.MyAspect;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
//代理类
public class CglibProxy implements MethodInterceptor{
    //代理方法
    public Object createProxy(Object target) {
        //创建一个动态类对象
        Enhancer enhancer = new Enhancer();
        //确定需要增强的类,设置其父类
        enhancer.setSuperclass(target.getClass());
        //添加回调函数
        enhancer.setCallback(this);
        //返回创建的代理类
        return enhancer.create();
    }
    /*
     * proxy CGlib根据指定父类生成的代理对象
     * method拦截的方法
     * args拦截的参数数组
     *methodProxy方法的代理对象,用于执行父类的方法
     */
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        //创建切面类对象
        MyAspect myAspect = new MyAspect();
        //前增强
        myAspect.check_Permission();
        //目标方法执行
        Object obj = methodProxy.invokeSuper(proxy, args);
        //后增强
        myAspect.log();
        return obj;
    }
}

2.3 创建测试类demo02_CglibTest.java 

package com.itheima;
import com.itheima.demo02.UserDao;
import com.itheima.demo02.CglibProxy;

public class CglibTest {
    public static void main(String[] args){
        //创建代理对象
        CglibProxy cglibProxy = new CglibProxy();
        //创建目标对象
        UserDao userDao = new UserDao();
        //从代理对象中获取增强后的目标对象
        UserDao userDao1 = (UserDao) cglibProxy.createProxy(userDao);
        //执行方法
        userDao1.addUser();
        userDao1.deleteUser();
    }
}

3.0 在src/main/java/com.itheima目录下创建demo03包。

3.1 创建接口UserDao.java,在该接口中编写添加用户、删除、修改和查询的方法。

package com.itheima.demo03;

public interface UserDao {
    public void insert();
    public void delete();
    public void update();
    public void select();
}

3.2  创建接口UserDao的实现类UserDaoImpl.java,实现UserDao接口中的方法。

package com.itheima.demo03;

public class UserDaoImpl implements UserDao {
    public void insert() {
        System.out.println("添加用户信息");
    }
    public void delete() {
        System.out.println("删除用户信息");
    }
    public void update() {
        System.out.println("更新用户信息");
    }
    public void select() {
        System.out.println("查询用户信息");
    }
}

3.3 创建XmlAdvice.java类,用于定义通知。

package com.itheima.demo03;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class XmlAdvice {
    //前置通知
    public void before(JoinPoint joinPoint){
        System.out.print("这是前置通知!");
        System.out.print("目标类是:"+joinPoint.getTarget());
        System.out.println(",被织入增强处理的目标方法为:"+ joinPoint.getSignature().getName());
    }
    //返回通知
    public void afterReturning(JoinPoint joinPoint){
        System.out.print("这是返回通知!");
        System.out.println("被织入增强处理的目标方法为:"+ joinPoint.getSignature().getName());
    }
    /*
    *环绕通知
    * ProceedingJoinPoint是JoinPoint子接口,表示可以执行目标方法
    * 1.必须是Object类型的返回值
    * 2.必须接收一个参数,类型为ProceedingJoinPoint
    * 3.必须是throws Throwable
     */
    public Object around(ProceedingJoinPoint point) throws Throwable{
        System.out.println("这是环绕通知之前的部分!");
        //调用目标方法
        Object object = point.proceed();
        System.out.println("这是环绕通知之后的部分!");
        return object;
    }
    //异常通知
    public void afterException(){
        System.out.println("异常通知!");
    }
    //后置通知
    public void after(){
        System.out.println("这是后置通知!");
    }
}

3.4 创建applicationContext.xml文件,在该文件中引入AOP命名空间,使用<bean>元素添加Spring 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: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 -->
    <bean name="userDao" class="com.itheima.demo03.UserDaoImpl"/>
    <bean name="xmlAdvice" class="com.itheima.demo03.XmlAdvice"/>
    <!-- 配置Spring AOP -->
    <aop:config>
        <!-- 指点切入点 -->
        <aop:pointcut id="pointcut" expression="execution(*
             com.itheima.demo03.UserDaoImpl.*(..))"/>
        <!-- 指定切面 -->
        <aop:aspect ref="xmlAdvice">
            <!-- 指定前置通知 -->
            <aop:before method="before" pointcut-ref="pointcut"/>
            <!-- 指定返回通知 -->
            <aop:after-returning method="afterReturning" pointcut-ref="pointcut"/>
            <!-- 指定环绕通知 -->
            <aop:around method="around" pointcut-ref="pointcut"/>
            <!-- 指定异常通知 -->
            <aop:after-throwing method="afterException" pointcut-ref="pointcut"/>
            <!-- 指定后置通知 -->
            <aop:after method="after" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

3.5 创建测试类demo03_TestXml.java 

package com.itheima;

import com.itheima.demo03.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestXml {
    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = context.getBean("userDao",UserDao.class);
        userDao.delete();
        System.out.println();
        userDao.insert();
        System.out.println();
        userDao.select();
        System.out.println();
        userDao.update();
    }
}

4.0 在src/main/java/com.itheima目录下创建demo04包。

4.1 创建AnnoAdvice.java类,用于定义通知。

package com.itheima.demo04;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect
public class AnnoAdvice {
    //切点
    @Pointcut("execution( * com.itheima.demo03.UserDaoImpl.*(..))")
    public void poincut(){}
    //前置通知
    @Before("poincut()")
    public void before(JoinPoint joinPoint){
        System.out.print("这是前置通知!");
        System.out.print("目标类是:"+joinPoint.getTarget());
        System.out.println(",被织入增强处理的目标方法为:"+ joinPoint.getSignature().getName());
    }
    //返回通知
    @AfterReturning("poincut()")
    public void afterReturning(JoinPoint joinPoint){
        System.out.print("这是返回通知!");
        System.out.println("被织入增强处理的目标方法为:"+ joinPoint.getSignature().getName());
    }
    //环绕通知
    @Around("poincut()")
    public Object around(ProceedingJoinPoint point) throws Throwable{
        System.out.println("这是环绕通知之前的部分!");
        //调用目标方法
        Object object = point.proceed();
        System.out.println("这是环绕通知之后的部分!");
        return object;
    }
    //异常通知
    @AfterThrowing("poincut()")
    public void afterException(){
        System.out.println("异常通知!");
    }
    //后置通知
    @After("poincut()")
    public void after(){
        System.out.println("这是后置通知!");
    }
}

4.2 创建applicationContext-Anno.xml文件,在该文件中引入AOP命名空间,使用<bean>元素添加Spring 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: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 -->
    <bean name="userDao" class="com.itheima.demo03.UserDaoImpl"/>
    <bean name="xmlAdvice" class="com.itheima.demo04.AnnoAdvice"/>
    <!-- 开启@aspectj的自动代理支持 -->
    <aop:aspectj-autoproxy/>
</beans>

4.3 创建测试类demo04_TestAnnotation.java 

package com.itheima;

import com.itheima.demo03.UserDao;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAnnotation {
    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext-Anno.xml");
        UserDao userDao = context.getBean("userDao",UserDao.class);
        userDao.delete();
        System.out.println();
        userDao.insert();
        System.out.println();
        userDao.select();
        System.out.println();
        userDao.update();
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_66697650/article/details/130256154