1.Aop解决的问题
- 当需要为多个不具有继承关系的对象引入同一个公共行为时,例如日志、安全检测等,我们只有在每个对象里引用公共行为,比如打印日志,这样程序中就产生了大量的重复代码,程序就不便于维护了,所以就有了一个对面向对象编程的补充,即面向方面编程(AOP),AOP所关注的方向是横向的,不同于OOP的纵向。
2.Aop的实现方式 - 静态 AOP 实现, AOP 框架在编译阶段对程序源代码进行修改,生成了静态的 AOP 代理类(生成的 *.class 文件已经被改掉了,需要使用特定的编译器),比如 AspectJ。
- 动态 AOP 实现, AOP 框架在运行阶段对动态生成代理对象(在内存中以 JDK 动态代理,或 CGlib 动态地生成 AOP 代理类),如 SpringAOP。
3.Aop的专有名词
- 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
- 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
- 切点(PointCut): 可以插入增强处理的连接点。
- 切面(Aspect): 切面是通知和切点的结合。
- 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
- 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。
4.第一个动态Aop实例:例如SSM框架中,Service层会有一些业务比如常见的增删改查,例如现在需要在插入数据成功之后打印下日志 - 引入依赖类AspectJ
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
- 创建要增强的行为:Service接口的实现类调mapper接口插入数据
public interface UserService {
int insertUser();
int update(SuperUser user);
}
/**
* @author ngLeede
* @version 1.0
* @Desc service的实现类
* @date 2021/6/10 22:07
*/
public class UserServiceImpl implements UserService {
private UserMapper userMapper;
public UserMapper getUserMapper() {
return userMapper;
}
public void setUserMapper(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Override
public int insertUser() {
userMapper.insertUser();
return 0;
}
@Override
public int update(SuperUser user) {
userMapper.update(user);
return 0;
}
}
/**
* @desc mapper接口
* @author ngLeede
* @date 2021/6/11 22:27
*/
public interface UserMapper {
int insertUser();
void update(SuperUser user);
}
/**
* @author ngLeede
* @version 1.0
* @Desc mapper接口的实现类,对应的行为是SSM框架里的mapper.xml
* @date 2021/6/10 22:06
*/
public class UserMapperImpl implements UserMapper {
@Override
public int insertUser() {
System.out.println("--插入数据--mapper接口--");
return 0;
}
@Override
public void update(SuperUser user) {
System.out.println("---修改超人信息---");
}
}
- 创建增强类实现aop的MethodBeforeAdvice 前置方法增强--具体要实现的功能是在调用Service层的方法前打印日志
/**
* @author ngLeede
* @version 1.0
* @Desc 增强类
* @date 2021/6/10 22:46
*/
public class MyAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
String mt = method.getName();
System.out.println("前置增强"+mt+"方法");
}
}
- 配置切点使前置增强方法能够作用于Service层的方法,在applicationContext.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
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--第一个aopyi 实例-->
<bean id="userMapper" class="com.ngLeede.aopyi.mapper.impl.UserMapperImpl"></bean>
<bean id="userService" class="com.ngLeede.aopyi.service.impl.UserServiceImpl">
<property name="userMapper" ref="userMapper" />
</bean>
<bean id="myadvice" class="com.ngLeede.aopyi.advice.MyAdvice"></bean>
<aop:config>
<!--切点表达式 增强service下的方法-->
<aop:pointcut id="ponitcut" expression="execution(* com.ngLeede.aopyi.service.*.*(..))"/>
<!--织入-->
<aop:advisor advice-ref="myadvice" pointcut-ref="ponitcut"/>
</aop:config>
</beans>
- 简单的测试
public class AppTest
{
/**
* @desc 測試第一Aop實例
* @author ngLeede
* @date 2021/6/10 22:12
*/
@Test
public void testAopyi(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) applicationContext.getBean("userService");
userService.insertUser();
SuperUser user = new SuperUser();
user.setName("超人");
user.setPhone("167777");
userService.update(user);
}
}