1.Aop概念
1.AOP叫做面向切面编程。
2.AOP是对OOP(面向对象编程)的补充。
3.AOP的核心是切面。就是对某个切入点做了通知进行增强扩展,形成横切面。可以实现在 不修改原有代码的情况下,做额外扩展。
4.AOP是对loC的补充。基于动态代理设计模式。
2.AOP中的专业术语
Aspect:切面。为方法添加增强功能的过程。
join point:切入点。就是我们平时说的目标方法,或说对哪个方法做扩展,做增强。
Advice:通知。就是增强内容。
Pointcut:切点。就是表达式(通过切点表达式可以找到需要增强功能的方法),通过表达 式说明哪些方法是join point。
AOP Proxy:代理。Spring支持JDK动态代理和cglib动态代理两种方式,可以通过proxy- target-class=true把默认的JDK动态代理修改为Cglib动态代理。
Weaving:织入。织入就是把Advice添加到join point的过程。
在实际开发中AOP主要应用在Service层。
之后Servlet调用的Service就是调的代理对象
3. 实现AOP的两种方式
在Spring中提供了两种方式实现AOP:
-
Schema-based:所有的通知都需要实现特定类型的接口实现通知。
-
AspectJ:可以使用普通Java类结合特定的配置实现通知
注意:它俩默认都是使用的JDK动态代理,但是同时也支持cglib动态代理。
1.Schema-based方式实现AOP(不常用,需要实现接口)
-
前置通知:在切入点之前执行的增强功能。通知需要实现MethodBeforeAdvice接口。
-
后置通知:在切入点之后执行的增强功能。通知需要实现AfterReturningAdvice接口。
-
环绕通知:一个方法包含了前置通知和后置通知的功能。通知需要实现MethodInterceptor接口。
-
异常通知:如果切入点中出现了异常(绝对不能try...catch解决了异常)就会触发异常通知。通知需要实现ThrowsAdvice接口。(实现接口,但是接口没有需要重写的方法但是我们要加入这个方法public void afterThrowing(Exception e){} 才行)
实例一:织入前置通知(实现MethodBeforeAdvice接口。)
接口
public interface UserService {
void method();
}
实现类 (直接利用注解将实现类交给spring容器管理)
@Service
public class UserServiceImpl implements UserService {
@Override
public void method() {
System.out.println("目标对象方法执行");
}
}
被织入的通知(利用注解交给容器管理)
@Component
public class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("这是前置通知");
System.out.println("目标方法"+method);
}
}
Spring中的配置
<!-- 交给注解实现就需要扫描到注解-->
<context:component-scan base-package="com.zqwl.advice,com.zqwl.service"/>
<!-- Aop配置-->
<aop:config>
<!-- 表达式中: 返回值类型 包.类.方法*代表任意(..代表方法参数类型任意) and 参数 ,返回值-->
<!-- 通过切入点表达式找到切点-->
<aop:pointcut id="aa" expression="execution(* com.zqwl.service.UserServiceImpl.method(..))"/>
<!-- 交给spring管理的类创建的实例以类名变小驼峰-->
<!-- advice-ref: 引用的通知 pointcut-ref:引用的切点-->
<aop:advisor advice-ref="beforeAdvice" pointcut-ref="aa"/>
</aop:config>
测试
写UserService userService 是由于默认是由Jdk实现的动态代理(基于接口)
将其切换成CJLIB之后就可以写成 UserServiceImpl userService了(基于实现类继承)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Test3 {
@Autowired
private UserService userService;
@Test
public void aa(){
//此时userService就是代理对象(结合了目标对象和通知对象)
userService.method();
}
}
2.AspectJ实现AOP
接口
public interface UserService {
void method();
}
实现类 (直接利用注解将实现类交给spring容器管理)
@Service
public class UserServiceImpl implements UserService {
@Override
public void method() {
System.out.println("目标对象方法执行");
}
}
被织入的通知的类(可以在类中写多个方法,再在配置中引用实现各种通知)(这儿我没用注解)
public class MyAdvice {
//前置通知
public void before(){
System.out.println("前置通知");
}
}
配置文件
<!--基于Aspectj方式配置 -->
<!-- 将需要织入的通知的类交给容器管理-->
<bean id="myAdvice" class="com.zqwl.advice.MyAdvice"/>
<!-- 切面配置-->
<aop:config>
<aop:aspect ref="myAdvice">
<aop:pointcut id="aa" expression="execution(* com.zqwl.service.UserServiceImpl.*(..))"/>
<!-- 配置前置通知-->
<aop:before method="before" pointcut-ref="aa"/>
</aop:aspect>
</aop:config>
<context:component-scan base-package="com.zqwl.service"/>
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext1.xml")
public class Test4 {
@Autowired
private UserService userService;
@Test
public void aa(){
userService.method();
}
}