面向切面的编程——AOP
AOP在Spring中的作用:1.提供声明式事务 2.允许用户实现自定义切面 3.不改变原有的代码,增加新的功能(其本质通过代理)
注解:不用写动态代理,简化开发。将公共业务(日志、安全、权限、缓存、事务)等与领域业务相结合,使领域业务更加纯粹。
专业词(部分,有时间再补充):
切面:Aspect 连接点:JoinPoint 通知:Advice 织入:Weaving
实现AOP的三种方式
1.使用Spring API实现AOP
- 建立Spring_Aop1工程
- 建立cn.jx.log包,创建Log.java(日志)
package cn.jx.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[]args, Object target)
throws Throwable{
System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行");
}
}
- 业务层示例
- 建cn.jx.service包,包下的UserService.java接口
package cn.jx.service;
public interface UserService {
public void add();
public void update();
public void delete();
public void search();
}
- 建cn.jx.serviceImpl包,包下的UserServiceImpl.java接口
package cn.jx.serviceImpl;
import cn.jx.service.UserService;
public class UserServiceImpl implements UserService {
@Override
public void add(){
System.out.println("增加用户");
}
public void update(){
System.out.println("修改用户");
}
public void delete(){
System.out.println("删除用户");
}
public void search(){
System.out.println("查询用户");
}
}
- beans.xml配置
- 导入AOP相关头文件 ,去官方文档找即可
- 建立userServiceImpl和Log之间的关系
- bean标签之前的全是头文件,没啥可看的,其实就下边6行代码
<?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:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.3.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-4.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd"
default-lazy-init="true">
<bean id = "userService" class="cn.jx.serviceImpl.UserServiceImpl"/>
<bean id = "Log" class="cn.jx.log.Log"/>
<!--为上面两个id建立关系,由Spring提供动态代理-->
<aop:config>
<aop:pointcut id="pointuct" expression="execution(* cn.jx.serviceImpl.UserServiceImpl.add())"/>
<aop:advisor advice-ref="Log" pointcut-ref="pointuct"/>
</aop:config>
</beans>
- 写Test方法,测试类
import cn.jx.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class AopTest {
@Test
public void aopTest(){
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) ac.getBean("userService");
userService.add();
}
}
实现结果截图
2.使用自定义类实现AOP
- 业务层service和serviceImpl都不变,Test也不变
- Log日志增加后置通知和before与after两个自定义方法
- 改beans.xml配置文件
- 修改后
execution(* cn.jx.serviceImpl.*.*(..))可以调用业务层里所有方法
- 改后的Log.java
package cn.jx.log;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
@Override
//前置通知
public void before(Method method, Object[]args, Object target)
throws Throwable{
System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行");
}
public void before(){
System.out.println("方法执行前");
}
//后置通知
public class AfterLog implements AfterReturningAdvice{
/**
*
* 目标方法执行后的通知
* @param method 被调用方法对象
* @param returnvalue 返回值
* @param target 目标对象
* @throws Throwable
*/
@Override
public void afterReturning(Object returnvalue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName() + "的" + method.getName() + "方法被执行,返回值:" +returnvalue);
}
}
public void after(){
System.out.println("方法执行后");
}
}
- 改后的beans.xml配置文件——头文件省略了啊
<bean id = "userService" class="cn.jx.serviceImpl.UserServiceImpl"/>
<bean id = "Log" class="cn.jx.log.Log"/>
<aop:config>
<aop:aspect ref="Log">
<!--cn.jx.serviceImpl包下所有类的所有方法的所有参数-->
<aop:pointcut id="pointcut" expression="execution(* cn.jx.serviceImpl.*.*(..))"/>
<!--前置通知-->
<aop:before method="before" pointcut-ref="pointcut"/>
<!--后置通知-->
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
实现结果截图
3.使用注解实现AOP(简单易用)
- beans.xml文件增加一句代码即可
<aop:aspectj-autoproxy/>
在Log.java中进行注解,代码如下
package cn.jx.log;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import java.lang.reflect.Method;
@Aspect //注解表示它是一个切面
public class Log {
@Before("execution(* cn.jx.service.*.*(..))")
public void before(){
System.out.println("方法执行前");
}
@After("execution(* cn.jx.service.*.*(..))")
public void after(){
System.out.println("方法执行后");
}
}
beans.xml
<bean id = "userService" class="cn.jx.serviceImpl.UserServiceImpl"/>
<bean id = "Log" class="cn.jx.log.Log"/>
<aop:aspectj-autoproxy/>