Spring系列四:AOP切面编程第四部分
基于XML配置AOP
- 🐋基于XML配置AOP
- 🐋课后作业
- 💗引出对Spring底层实现再思考
- 🐋创建maven项目
🐋基于XML配置AOP
●基本说明
前面我们是通过注解来配置aop的, 在spring中, 我们也可以通过xml的方式来配置AOP.
●代码实现
1.将SmartAnimalAble.java
,SmartDog.java
拷贝至 spring/aop/xml
包下 注意: 不要引错包
2.新建切面类com.zzw.spring.aop.xml.SmartAnimalAspect
//这是我们开发的一个切面类, 但是不用注解, 而是使用xml配置
public class SmartAnimalAspect {public void showBeginLog(JoinPoint joinPoint) {//通过连接点对象joinPoint, 可以获取方法签名Signature signature = joinPoint.getSignature();System.out.println("SmartAnimalAspect[XML配置]-切面类showBeginLog()-方法执行前-日志-方法名-" + signature.getName() + "-参数 "+ Arrays.asList(joinPoint.getArgs()));}public void showSuccessEndLog(JoinPoint joinPoint, Object res) {Signature signature = joinPoint.getSignature();System.out.println("SmartAnimalAspect[XML配置]-切面类showSuccessEndLog()-方法执行正常结束-日志-方法名-" + signature.getName() + " 返回的结果是=" + res);}public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {Signature signature = joinPoint.getSignature();System.out.println("SmartAnimalAspect[XML配置]-切面类showExceptionLog()-方法执行异常-日志-方法名-" + signature.getName() + " 异常信息=" + throwable);}public void showFinallyEndLog(JoinPoint joinPoint) {Signature signature = joinPoint.getSignature();System.out.println("SmartAnimalAspect[XML配置]-切面类showFinallyEndLog()-方法最终执行完毕-日志-方法名-" + signature.getName());}
}
3.新建src/beans09_2.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/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"><!--使用XML配置, 完成AOP编程--><!--配置一个切面类对象-bean--><bean class="com.zzw.spring.aop.xml.SmartAnimalAspect" id="smartAnimalAspect"/><!--配置一个SmartDog对象-bean--><bean class="com.zzw.spring.aop.xml.SmartDog" id="smartDog"/><!--配置切面类, 细节: 一定要引入 xmlns:aop--><aop:config><!--配置切入点表达式--><aop:pointcut id="myPointCut" expression="execution(public float com.zzw.spring.aop.xml.SmartDog.getSum(float, float))"/><!--配置切面的 前置,返回,异常,最终通知--><aop:aspect ref="smartAnimalAspect" order="10"><!--配置前置通知--><aop:before method="showBeginLog" pointcut-ref="myPointCut"/><!--配置返回通知--><aop:after-returning method="showSuccessEndLog" pointcut-ref="myPointCut" returning="res"/><!--配置异常通知--><aop:after-throwing method="showExceptionLog" pointcut-ref="myPointCut" throwing="throwable"/><!--配置最终通知--><aop:after method="showFinallyEndLog" pointcut-ref="myPointCut"/><!--配置环绕通知--><!--<aop:around method=""--></aop:aspect></aop:config>
</beans>
4.测试com.zzw.spring.aop.xml.AopAspectjXMLTest
public class AopAspectjXMLTest {@Testpublic void testAspectByXML() {ApplicationContext ioc = new ClassPathXmlApplicationContext("beans09_2.xml");SmartAnimalAble smartAnimalAble = ioc.getBean(SmartAnimalAble.class);smartAnimalAble.getSum(1, 2);}
}
🐋课后作业
1.请编写一个Cal
接口
(1)方法 cal1(int n) 计算1 + 2 +...+ n
(2)方法 cal2(int n) 计算 1 * 2 *...* n
2.实现类 MyCal
, 实现Cal
的方法
3.请分别使用 注解方式 / XML配置方式
完成AOP编程
(1) 在执行cal1 前打印开始执行的时间, 执行完后打印结束的时间
(2) 在执行cal2 前打印开始执行的时间, 执行完后打印结束的时间
❶👉基于注解
1.新建com.zzw.spring.aop.homework02.annotation_.Cal
接口
public interface Cal {//计算1+2+...+nint cal1(int n);//计算1*2*...*nint cal2(int n);
}
2.新建实现类com.zzw.spring.aop.homework02.annotation_.MyCal
@Component
public class MyCal implements Cal{@Overridepublic int cal1(int n) {int sum = 0;for (int i = 1; i <= n; i++) {sum += i;}return sum;}@Overridepublic int cal2(int n) {int res = 1;for (int i = 1; i <= n; i++) {res *= n;}return res;}
}
3.新建切面类com.zzw.spring.aop.homework02.annotation_.CalAspect
日期类指引
@Aspect //CalAspect是一个切面类
@Component //CalAspect作为对象, 注入到Spring容器
public class CalAspect {//注意: 如果目标类和切面类, 在同一个包, 可以省略包名//因为cal1和cal2方法, 都要去输出开始执行时间, 因此使用 MyCal.* 通配符@Pointcut(value = "execution(public int MyCal.*(int))")public void myPointCut() {}//前置通知@Before(value = "myPointCut()")public void calStart(JoinPoint joinPoint) {Signature signature = joinPoint.getSignature();System.out.println(signature.getName() + " 执行, 开始执行时间=" + System.currentTimeMillis());}//返回通知@AfterReturning(value = "myPointCut()", returning = "res")public void calEnd(JoinPoint joinPoint, Object res) {Signature signature = joinPoint.getSignature();System.out.println(signature.getName() + " 执行结果=" + res);System.out.println(signature.getName() + " 执行, 执行结束时间=" + System.currentTimeMillis());}
}
4.新建src/beans10.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: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"><!--扫描指定的包--><context:component-scan base-package="com.zzw.spring.aop.homework02.annotation_"/><!--开启基于注解的AOP功能--><aop:aspectj-autoproxy/>
</beans>
5.测试com.zzw.spring.aop.homework02.annotation_.AopAspectjTest
public class AopAspectjTest {@Testpublic void test() {ApplicationContext ioc =new ClassPathXmlApplicationContext("beans10.xml");Cal cal = ioc.getBean(Cal.class);cal.cal1(10);System.out.println("====================================");cal.cal2(10);}
}
6.结果
cal1 执行, 开始执行时间=1691395310255
cal1 执行结果=55
cal1 执行, 结束时间=1691395310256
====================================
cal2 执行, 开始执行时间=1691395310256
cal2 执行结果=1410065408
cal2 执行, 结束时间=1691395310257
❷基于XML配置方法
1.新建com.zzw.spring.aop.homework02.xml.Cal
接口
public interface Cal {//计算1+2+...+nint cal1(int n);//计算1*2*...*nint cal2(int n);
}
2.新建实现类com.zzw.spring.aop.homework02.xml.MyCal
public class MyCal implements Cal{@Overridepublic int cal1(int n) {int sum = 0;for (int i = 1; i <= n; i++) {sum += i;}return sum;}@Overridepublic int cal2(int n) {int res = 1;for (int i = 1; i <= n; i++) {res *= ;}return res;}
}
3.新建切面类com.zzw.spring.aop.homework02.xml.CalAspect
public class CalAspect {//前置通知public void calStart(JoinPoint joinPoint) {Signature signature = joinPoint.getSignature();System.out.println(signature.getName() + " 方法[基于XML配置], 开始执行时间=" + System.currentTimeMillis());}//返回通知public void calEnd(JoinPoint joinPoint, Object res) {Signature signature = joinPoint.getSignature();System.out.println(signature.getName() + " 执行结果=" + res);System.out.println(signature.getName() + " 方法[基于XML配置], 执行结束时间=" + System.currentTimeMillis());}
}
4.新建src/beans11.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 https://www.springframework.org/schema/aop/spring-aop.xsd"><!--使用XML配置, 完成AOP编程--><!--配置一个切面类对象-bean--><bean class="com.zzw.spring.aop.homework02.xml.CalAspect" id="calAspect"/><!--配置一个MyCal对象-bean--><bean class="com.zzw.spring.aop.homework02.xml.MyCal" id="myCal"/><!--配置切面类, 细节: 一定要引入 xmlns:aop--><aop:config><!--配置切入点表达式--><aop:pointcut id="myPointCut" expression="execution(public int com.zzw.spring.aop.homework02.xml.MyCal.*(int))"/><!--配置切面的 前置, 返回通知--><aop:aspect ref="calAspect" order="10"><!--配置前置通知--><aop:before method="calStart" pointcut-ref="myPointCut"/><!--配置返回通知--><aop:after-returning method="calEnd" pointcut-ref="myPointCut" returning="res"/></aop:aspect></aop:config>
</beans>
5.测试com.zzw.spring.aop.homework02.xml.AopAspectjTest
public class AopAspectjXMLTest {@Testpublic void testMyCalByXML() {ApplicationContext ioc =new ClassPathXmlApplicationContext("beans11.xml");Cal cal = ioc.getBean(Cal.class);cal.cal1(10);System.out.println("====================================");cal.cal2(10);}
}
6.结果
cal1 执行[基于XML配置], 开始执行时间=1691396329275
cal1 执行结果=55
cal1 执行[基于XML配置], 执行结束时间=1691396329275
====================================
cal2 执行[基于XML配置], 开始执行时间=1691396329275
cal2 执行结果=1410065408
cal2 执行[基于XML配置], 执行结束时间=1691396329275
💗引出对Spring底层实现再思考
🐋创建maven项目
1.创建maven项目 zzw-spring项目
2.加入依赖pom.xml
<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/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.zzw</groupId><artifactId>zzw-spring</artifactId><version>1.0-SNAPSHOT</version><dependencies><!--加入spring开发的基本包--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.8</version></dependency><!--加入spring开发切面编程需要的包--><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.8</version></dependency></dependencies>
</project>
项目目录结构, 文件夹对应不上的可以自己 添加或删除.
3.新建com.zzw.spring.component.UserAction
//就是一个Controller
//也可以使用 @Controller
在默认情况下, 我们配置@Component,@Repository,@Controller,@Service 是单例
@Component
public class UserAction { }
4.新建com.zzw.spring.component.UserDao
//也可以使用 @Repository
@Component
public class UserDao {public void hi() {System.out.println("UserDao hi()...");}
}
5.新建com.zzw.spring.component.UserService
//也可以使用 @Service
@Component
public class UserService {//也可以使用 @Resource@Autowiredprivate UserDao userDao;//定义一个属性public void m1() {userDao.hi();}
}
5.新建src/beans.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:context="http://www.springframework.org/schema/context"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"><!--配置自动扫描的包, 同时引入对应的名称空间--><context:component-scan base-package="com.zzw.spring.component"/></beans>
6.测试1com.zzw.spring.AppMain
public class AppMain {public static void main(String[] args) {//测试/看看是否可以得到spring容器中的bean, 同时看看依赖注入是否OKApplicationContext ioc =new ClassPathXmlApplicationContext("beans.xml");UserAction userAction = ioc.getBean("userAction", UserAction.class);UserAction userAction2 = ioc.getBean("userAction", UserAction.class);System.out.println("userAction=" + userAction);System.out.println("userAction2=" + userAction2);UserDao userDao = ioc.getBean("userDao", UserDao.class);System.out.println("userDao=" + userDao);UserService userService = ioc.getBean("userService", UserService.class);System.out.println("userService=" + userService);}
}
报错: Caused by: java.io.FileNotFoundException: class path resource [beans.xml] cannot be opened because it does not exist
, 其错误原因是
7.实际上 beans.xml
应该在 src/main/resources
下创建
<?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"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"><!--配置自动扫描的包, 同时引入对应的名称空间--><!--说明1.如果我们是普通的java项目, beans.xml放在src目录下即可2.如果我们是java maven项目, beans.xml放在src/main/resources--><context:component-scan base-package="com.zzw.spring.component"/></beans>
此时项目结构图如下所示:
8.运行结果
userAction=com.zzw.spring.component.UserAction@679b62af
userAction2=com.zzw.spring.component.UserAction@679b62af
userDao=com.zzw.spring.component.UserDao@5cdd8682
userService=com.zzw.spring.component.UserService@d6da883