一、首先回顾原始AOP开发流程
1.原始对象
2.额外功能
3.切入点
4.组装切面
二、基于注解的AOP开发
#所需要的注解
# 通过切面类
定义了 额外功能 @Around
定义切入点 @Around("execution(* login(..))")
@Aspect 将自定义的类指定为切面类
1、构建原始对象(service实现类)----实现核心功能代码
2、切面类的开发
@Apect
public class MyApect{
@Around("execution(* login(..))")
public Object arround(ProceedingJoinPoint joinPoint)throws Throwable{
System.out.println("前置增强的额外功能..........+++++++ 事务管理功能----");
Object ret = joinPoint.proceed();
System.out.println("后置增强的额外功能.......++++++++ 事务管理功能-------");
return ret;
}
@Around("execution(* login(..))")
public Object arround1(ProceedingJoinPoint joinPoint)throws Throwable{
System.out.println("前置增强的额外功能..........+++++++ 性能监测-----");
Object ret = joinPoint.proceed();
System.out.println("后置增强的额外功能.......++++++++ 性能监测-------");
return ret;
}
@Around("execution(* login(..))")
public Object arround2(ProceedingJoinPoint joinPoint)throws Throwable{
System.out.println("前置增强的额外功能..........+++++++ 日志功能 -----");
Object ret = joinPoint.proceed();
System.out.println("后置增强的额外功能.......++++++++ 日志功能-------");
return ret;
}
}
2、配置文件的编写
<?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">
<bean id="userService" class="com.xxx.service.impl.UserServiceImpl"/>
<!-- 将切面类交给工厂管理-->
<bean id="arrount" class="com.xxx.aspect.MyAspect"></bean>
<!--告知Spring工厂基于注解进行AOP编程-->
<aop:aspectj-autoproxy/>
</beans>
3、测试
@Test
public void testAspect(){
ClassPathXmlApplicationContext c = new ClassPathXmlApplicationContext("/applicationContext3.xml");
UserService arrount =(UserService) c.getBean("userService");
arrount.login("ss","ss");
}
结果
4、冗余代码抽取
由第一版切面类可知---注解值切入点出现了重复性的使用
简化切面类开发---抽取共性 ---使用 @Pointcut()标签
@Apect
public class MyApect{
@Pointcut("execution(* login(..))")
public void myPointCut(){}//指定切入点
@Around(value="myPointCut()")
public Object arround(ProceedingJoinPoint joinPoint)throws Throwable{
System.out.println("前置增强的额外功能..........+++++++ log-----");
Object ret = joinPoint.proceed();
System.out.println("后置增强的额外功能.......++++++++ log-------");
return ret;
}
@Around(value="myPointCut()")
public Object arround1(ProceedingJoinPoint joinPoint)throws Throwable{
System.out.println("前置增强的额外功能..........+++++++ 性能监测-----");
Object ret = joinPoint.proceed();
System.out.println("后置增强的额外功能.......++++++++ 性能监测-------");
return ret;
}
@Around(value="myPointCut()")
public Object arround2(ProceedingJoinPoint joinPoint)throws Throwable{
System.out.println("前置增强的额外功能..........+++++++ tx -----");
Object ret = joinPoint.proceed();
System.out.println("后置增强的额外功能.......++++++++ tx-------");
return ret;
}
}
5、动态代理的创建方式
AOP的底层实现有两种实现方式
1. 基于JDK 通过实现接口,做新的实现类[动态生成的] 创建代理对象
2. CGLIB 代理类通过继承原始类 完成代理对象的创建
默认情况下,AOP底层应用的是JDK动态代理创建方式
如果切换为 CGLIB
1.传统的AOP开发[基于配置文件完成组装] proxy-target-class="true"-----基于CGLIB false[JDK]
<aop:config proxy-target-class="true">
<!--定义切入点-->
<aop:pointcut id="pc" expression="!execution(* login(..))"/>
<aop:advisor advice-ref="myInterceptor" pointcut-ref="pc"/>
</aop:config>
2.基于直接的AOP开发
<aop:aspectj-autoproxy proxy-target-class="true"/>
proxy-target-class="true"-----基于CGLIB false[JDK]
6、注意事项
在同一个业务类中,进行业务方法间的调用时,只有最外层的方法,才会加入额外功能(内部方法时通过普通的方式在原始类中调取的,并没有加入额外功能)。如果想内层的方法也调用代理对象的方法,因该先获取代理对象,再调方法
实现逻辑:
1、使原始类实现ApplicationContextAware接口----它只有一个方法
2、实现接口中的方法
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.ctx = ctx;
}
这里的this.ctx 我们需要设置一个ApplicationContext ctx(变量名) 类型的属性
这个方法的返回值就是Spring工厂对象,获取动态代理对象的方法我们可以通过getBean()方法来获取动态代理对象
原始类:
public class UserServiceImpl implements UserService, ApplicationContextAware {
private ApplicationContext ctx;
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.ctx = ctx;
}
@Override
public User login(String uname, String pwd) {
System.out.println("UserServiceImpl ----- login(String uname,String pwd)...... 核心功能的编码");
return new User();
}
@Log
@Override
public void regist(User user) {
System.out.println("UserServiceImpl ----- regist(User user)...... 核心功能的编码");
}
@Override
public User login(String name) {
System.out.println("UserServiceImpl ----- login(String uname)...... 核心功能的编码");
return new User();
}
/*
工厂属于重量级资源,一个应用中应该只创建一个工厂-----》 等待外界传递
ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext2.xml");
UserService service = ctx.getBean("userService", UserService.class); // 代理对象
service.login("小黑","666666");
代理对象需要借助于工厂
需要工厂!!!
public void dropById(Integer id) {
this.login("小黑","666666"); // 当前目标对象的login方法 ------>更换为调用代理对象的login
System.out.println("dropById............. 核心功能的编码");
}
*/
@Override
public void dropById(Integer id) {
UserService service = ctx.getBean("userService", UserService.class); // 代理对象
service.login("小黑","666666");
System.out.println("dropById............. 核心功能的编码");
}
}