【案例介绍】
(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();
}
}