文章目录
1. Spring中的AOP简介
- AOP(Aspect Oriented Programming)
2 代理模式
3. AOP的专业术语
- Joinpoint(连接点):目标类中可以被增强的方法
- Pointcut(切入点/切点):目标类中要被增强的方法
- Advice(通知/增强):增强的代码
- 前置增强(通知)
- 后置增强(通知)
- 环绕增强(通知)
- Target(目标对象):目标对象
- Weaving(织入):把增强应用切点的过程
- Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类
- Aspect(切面):切点和通知的结合
4. 基于Jdk动态代理实现自定义AOP
-
pom依赖
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.10.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.10</version> </dependency> </dependencies>
-
创建接口
UserService
public interface UserService { void addUser(); void deleteUser(); }
-
定义目标类
UserServiceImpl
public class UserServiceImpl implements UserService { @Override public void addUser() { System.out.println("添加用户"); } @Override public void deleteUser() { System.out.println("删除用户"); } }
-
定义切面
MyAspect
public class MyAspect { public void before() { System.out.println("前置通知"); } public void after() { System.out.println("后置通知"); } public void around() { System.out.println("环绕通知"); } }
-
定义目标对象的工厂类(用于创建目标对象说对应的代理对象)
UserServiceFactory
public class UserServiceFactory { public UserService newUserServiceProxy() { //创建目标对象 UserServiceImpl userService = new UserServiceImpl(); //创建切面对象 MyAspect myAspect = new MyAspect(); //创建代理对象 UserService userServiceProxy = (UserService) Proxy.newProxyInstance(UserServiceFactory.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { myAspect.before(); Object result = method.invoke(userService, args); myAspect.after(); return result; } }); return userServiceProxy; } }
-
入口类
public static void main(String[] args) { UserServiceFactory factory = new UserServiceFactory(); UserService userService = factory.newUserServiceProxy(); userService.addUser(); }
5. AOP联盟定义的通知类型
Spring按照通知(Advice)在目标类方法的切点的位置,分为5类:
- 前置通知
org.springframework.aop.MethodBeforeAdvice
- 在目标方法执行前实施增强
- 后置通知
org.springframework.aop.AfterReturningAdvice
- 在目标方法执行后实施增强
- 环绕通知
org.aopalliance.intercept.MethodInterceptor
- 在目标方法执行前后实施增强,环绕通知,必须手动执行目标方法
- 异常抛出通知
org.springframework.aop.ThrowsAdvice
- 在方法抛出异常后实施增强
- 引介通知
org.springframework.aop.IntroductionInterceptor
- 在目标类中添加一些新的方法和属性
6. Spring中的AOP(不建议使用)
6.1 Spring中的半自动AOP
-
定义接口
public interface UserService { void addUser(); void deleteUser(); }
-
定义目标类
public class UserServiceImpl implements UserService { @Override public void addUser() { System.out.println("添加用户"); } @Override public void deleteUser() { System.out.println("删除用户"); } }
-
定义切面(实现Spring提供的拦截器)
public class MyAspect implements org.aopalliance.intercept.MethodInterceptor { //定义三个通知 public void before() { System.out.println("前置通知"); } public void after() { System.out.println("后置通知"); } public void around() { System.out.println("环绕通知"); } @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { before(); Object result = methodInvocation.proceed(); after(); return result; } }
-
配置Spring中自带的工厂
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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--<bean id="userServiceFactory" class="com.it.framework.UserServiceFactory"></bean>--> <!--定义目标对象--> <bean id="userServiceImpl" class="com.it.framework.UserServiceImpl"></bean> <!--定义切面对象--> <bean id="myAspect" class="com.it.framework.MyAspect"></bean> <!--定义工厂对象--> <bean id="userServiceproxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <!--配置接口--> <property name="interfaces" value="com.it.framework.UserService"/> <!--配置目标对象--> <property name="targetName" value="userServiceImpl"/> <!--配置拦截器--> <property name="interceptorNames" value="myAspect"/> <!--配置动态代理方式,true是使用cglib的方式,默认使用jdk的动态代理--> <property name="optimize" value="true"></property> </bean> </beans>
6.2 Spring中的全自动AOP
-
pom依赖
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.3.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.10.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.3.10.RELEASE</version> </dependency> <!--spring全自动aop依赖aspectj联盟的依赖--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.10</version> </dependency> </dependencies>
-
定义接口===>同半自动AOP一致
-
定义目标类===>同半自动AOP一致
-
定义切面(实现Spring提供的拦截器)===>同半自动AOP一致
-
配置
applicationContext.xml
<!--定义目标对象--> <bean id="userServiceImpl" class="com.it.framework.UserServiceImpl"></bean> <!--定义切面对象--> <bean id="myAspect" class="com.it.framework.MyAspect"></bean> <!-- proxy-target-class=true表示使用cglib动态代理 --> <aop:config proxy-target-class="true"> <!--定义切点表达式--> <aop:pointcut id="myPointCut" expression="execution(* com.it.framework.UserServiceImpl.*(..))"/> <aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"></aop:advisor> </aop:config>
-
入口类
<!--定义目标对象--> <bean id="userServiceImpl" class="com.it.framework.UserServiceImpl"></bean> <!--定义切面对象--> <bean id="myAspect" class="com.it.framework.MyAspect"></bean> <!-- proxy-target-class=true表示使用cglib动态代理 --> <aop:config proxy-target-class="true"> <!--定义切点表达式--> <aop:pointcut id="myPointCut" expression="execution(* com.it.framework.UserServiceImpl.*(..))"/> <aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"></aop:advisor> </aop:config>
7. 切点表达式
-
用于描述需要增强的方法(切点)
-
语法
execution(修饰符 返回值 包.类.方法名(参数) throws异常)
-
修饰符,一般省略
public 公共方法 * 任意
-
返回值类型,不能省略
void 返回没有值 String 返回值字符串 * 任意
-
包 可以省略
~~~java
com.it.spring 固定包
com.it.spring… spring包下面的所有子包(含自己) -
任意
~~~
-
类,可以省略
UserServiceImpl 指定类 *Impl 以Impl结尾 User* 以User开头 * 任意
-
方法名,不能省略
addUser 固定方法 add* 以add开头 *Do 以Do结尾 * 任意
-
(参数)
() 无参 (int) 一个整型 (int ,int) 两个 (..) 参数任意
-
throws ,可省略,一般不写
-
eg
UserServiceImpl类中任意参数的方法 * com.it.framework.UserServiceImpl.*(..)
9. 基于Aspectj的AOP
- AspectJ是一个基于Java语言的面向切面的AOP框架
- Spring2.0以后新增了对AspectJ切点表达式支持
- @AspectJ 是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面
- 新版本Spring框架,建议使用AspectJ方式来开发AOP
9.1 AspectJ的增强类型
- @Before 前置通知,相当于BeforeAdvice
@Before("execution(* com.uplooking.aop.UserDao.add*(..))")
public void beforeAdvice() {
System.out.println("前置通知....");
}
- @AfterReturning 后置通知,相当于AfterReturningAdvice
@AfterReturning(value = "execution(* com.uplooking.aop.UserDao.add*(..))", returning = "ret")
public void afterReturningAdvice(String ret) {
System.out.println("后置通知.." + ret);
}
- @Around 环绕通知,相当于MethodInterceptor
@Around("execution(* com.uplooking.aop.UserDao.add*(..))")
public void arounrAdvice(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("环绕通知前..");
pjp.proceed();
System.out.println("环绕通知后..");
}
- @AfterThrowing抛出通知,相当于ThrowAdvice
@AfterThrowing("execution(* com.uplooking.aop.UserDao.add*(..))")
public void throwAdvice() {
System.out.println("异常通知....");
}
- @After 最终final通知,不管是否异常,该通知都会执行
@After(value = "execution(* com.uplooking.aop.UserDao.add*(..))")
public void afterAdvice() {
System.out.println("最终通知....");
}
9.2. 基于Aspectj的Aop
- pom依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
<!--Spring整合Aspectj的包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
-
定义切面
切面 = 切点 + 通知
/**
* 切面 = 切点(切点表达式) + 通知(方法)
*/
@Aspect
@Component
public class MyAspect {
@Before("execution(* add*(..))")
public void beforeAdvice() {
System.out.println("前置通知....");
}
}
- 定义要增强的类
@Repository
public class UserDao {
public void add() {
System.out.println("添加用户...");
}
public void add1() {
System.out.println("add1...");
}
public void delete() {
System.out.println("删除用户...");
}
public void update() {
System.out.println("修改用户...");
}
public void select() {
System.out.println("查询用户...");
}
}
- 配置
applicationContext.xml
<!--组件扫描器-->
<context:component-scan base-package="com.uplooking.aop"/>
<!--aop自动创建代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 测试程序
@RunWith(SpringRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class UserDaoTest {
@Autowired
private UserDao userDao;
//edu.uplooking.com passwd :80684
@Test
public void testAdd() {
userDao.add();
userDao.add1();
}
}