@AOP思想简介,Spring AOP 简介
第一次以博客的形式来记录学习过程,希望对一些人有帮助,更希望大牛指出错误
AOP思想
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
AOP思想的体现
1
在Java web 的 servlet 中要解决乱码问题,如果每一个方法中都要解决乱码,就会产生很多的重复 性代码,这时就可以使用Filter,在Filter中解决乱码问题,然后再取web.xml文件中配置,就可以实现解决乱码只需要书写一次
2 在struts2拦截器中也能体现aop思想
Spring AOP
在Spring中aop是通过代理技术来体现的,代理简单来说就是增强方法,spring中封装了动态代理和cglib代理,这就意味着,在spring中我们不需要去写实现代理的代码,只需要在配置文件中配置即可
动态代理和cglib代理的区别
1.动态代理被代理对象必须要实现接口,才能产生代理对象.如果没有接口将不能使用动态代理技术
2.cglib代理是第三方代理技术,cglib代理.可以对任何类生成代理.代理的原理是对目标对象进行继承代理. 如果目标对象被final修饰.那么该类无法被cglib代理.
spring中的aop演示
1- 准备目标对象
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("保存用户!");
//int i = 1/0;
}
@Override
public void delete() {
System.out.println("删除用户!");
}
@Override
public void update() {
System.out.println("更新用户!");
}
@Override
public void find() {
System.out.println("查找用户!");
}
}
2- 准备通知(要被增强的代码)
//通知类
public class MyAdvice {
//前置通知
// |-目标方法运行之前调用
//后置通知(如果出现异常不会调用)
// |-在目标方法运行之后调用
//环绕通知
// |-在目标方法之前和之后都调用
//异常拦截通知
// |-如果出现异常,就会调用
//后置通知(无论是否出现 异常都会调用)
// |-在目标方法运行之后调用
//----------------------------------------------------------------
//前置通知
public void before(){
System.out.println("这是前置通知!!");
}
//后置通知
public void afterReturning(){
System.out.println("这是后置通知(如果出现异常不会调用)!!");
}
//环绕通知
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("这是环绕通知之前的部分!!");
Object proceed = pjp.proceed();//调用目标方法
System.out.println("这是环绕通知之后的部分!!");
return proceed;
}
//异常通知
public void afterException(){
System.out.println("出事啦!出现异常了!!");
}
//后置通知
public void after(){
System.out.println("这是后置通知(出现异常也会调用)!!");
}
}
3 - 配置进行织入,将通知织入目标对象中
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
<!-- 准备工作: 导入aop(约束)命名空间 -->
<!-- 1.配置目标对象(就是要被代理的对象) -->
<bean name="userService" class="com.itheima.service.UserServiceImpl"></bean>
<!-- 2.配置通知对象 -->
<bean name="myAdvice" class="com.itheima.d_springapo.MyAdvice"></bean>
<!-- 3.配置将通知,织入目标对象 -->
<aop:config>
<!-- 配置切入点
public void cn.itcast.service.UserServiceImpl.save()
void cn.itcast.service.UserServiceImpl.save()
* cn.itcast.service.UserServiceImpl.save() 第一个星号代表返回值可以为任何类型
* cn.itcast.service.UserServiceImpl.*() 第二的星号代表cn.itcast.service.UserServiceImpl下的所有方法
* cn.itcast.service.*ServiceImpl.*(..) cn.itcast.service包下以ServiceImpl为后缀的类的所有方法,(..)代表参数不限制,可以有可以没有
* cn.itcast.service..*ServiceImpl.*(..) cn.itcast.service包下以及子包下,以ServiceImpl为后缀的类的所有方法
-->
<!-- expression:表达式里填的是要被增强的方法 -->
<!-- expression属性中要填方法的全方法名
execution(* com.itheima.service.*ServiceImpl.*(..))
com.itheima.service包下的以ServiceImpl为后缀的类中的所有方法,方法中的参数可以有可以没有
-->
<aop:pointcut expression="execution(* com.itheima.service.*ServiceImpl.*(..))" id="pc" />
<!-- ref属性:填的是,通知对象 -->
<aop:aspect ref="myAdvice">
<!-- 指定名为before方法作为前置通知 -->
<!-- 将通知类中的before方法作为前置对象,切入到pc中 -->
<aop:before method="before" pointcut-ref="pc" />
<!-- 后置 -->
<aop:after-returning method="afterReturning"
pointcut-ref="pc" />
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pc" />
<!-- 异常拦截通知 -->
<aop:after-throwing method="afterException"
pointcut-ref="pc" />
<!-- 后置 -->
<aop:after method="after" pointcut-ref="pc" />
</aop:aspect>
</aop:config>
</beans>
4 - 测试spring aop
//帮我们创建容器
@RunWith(SpringJUnit4ClassRunner.class)
//指定创建容器时使用哪个配置文件
@ContextConfiguration("classpath:com/itheima/d_springapo/applicationContext.xml")
public class Demo {
//将名为userService的对象注入到us变量中,这样获取到的UserService对象就是代理对象
@Resource(name="userService")
private UserService us;
@Test
public void fun1(){
us.save();
}
}
结果:
这是环绕通知之前的部分!!
这是前置通知!!
保存用户!
这是环绕通知之后的部分!!
这是后置通知(出现异常也会调用)!!
这是后置通知(如果出现异常不会调用)!!
图中的通知就是上面的通知类,根据不同是时机spring给了5个方法(具体配置参考上方配置文件)
//前置通知
// |-目标方法运行之前调用
//后置通知(如果出现异常不会调用)
// |-在目标方法运行之后调用
//环绕通知
// |-在目标方法之前和之后都调用
//异常拦截通知
// |-如果出现异常,就会调用
//后置通知(无论是否出现 异常都会调用)
// |-在目标方法运行之后调用
通知里面写的就是要增强的代码,经过配置文件的配置,会将通知类里面的代码织入要增强的方法中(本次测试是将目标对象的所有方法都增强),经过所有的配置后spring后自动生成代理对象,再次从spring取出的UserService对象就是代理对象