上面这两种代理的方式不好,需要为每一个类配置一个独立的ProxyFactoryBean.(如果需要代理的类特别的多,每个类都需要创建一个代理的类.)
根据切面Advisor的定义的信息,看到哪些类的哪些方法需要增强.(为这些需要增强的类生成代理.
自动代理:基于后处理BeanPostProcessor完成代理.
代理机制不同
基于ProxyFactoryBean代理:先有被代理对象,将被代理对象传递给代理对象,为其生成代理.
自动代理:基于BeanPostProcessor代理.在生成类的过程中产生一个代理对象,返回的就是代理对象本身.
BeanNameAutoProxyCreator 根据Bean名称创建代理
DefaultAdvisorAutoProxyCreator 根据Advisor本身包含信息创建代理
AnnotationAwareAspectJAutoProxyCreator 基于Bean中的AspectJ 注解进行自动代理
== > BeanNameAutoProxyCreator:
<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="*Dao"/>
<property name="interceptorNames" value="beforeAdvice"/>
bean>
<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="pattern" value="cn\.itcast\.spring3\.demo4\.CustomerDao\.add.*"/>
<property name="advice" ref="aroundAdvice"/>
bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">bean>
区分:
代理机制不同:
基于ProxyFactoryBean代理:先有被代理对象,将被代理对象传递给代理对象,为其生成代理.
自动代理:基于BeanPostProcessor代理.在生成类的过程中产生一个代理对象,返回的就是代理对象本身.
2.1 什么是AspectJ
Spring为了简化AOP的开发,引入AspectJ技术.
AspectJ是一个面向切面的框架,它扩展了Java语言。AspectJ定义了AOP语法所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。
Spring2.0以后新增了对AspectJ切点表达式支持
@Before 前置通知,相当于BeforeAdvice
@AfterReturning 后置通知,相当于AfterReturningAdvice
@Around 环绕通知,相当于MethodInterceptor
@AfterThrowing抛出通知,相当于ThrowAdvice
@After 最终final通知,不管是否异常,该通知都会执行
@DeclareParents 引介通知,相当于IntroductionInterceptor (不要求掌握)
配置哪些类的哪些方法需要使用增强:
* 类似于正则的方法切点切面.
语法:
execution(<访问修饰符>?<返回类型><方法名>(<参数>)<异常>)
例如:
execution(* *(..));
execution(* cn.itcast.spring3.demo1.UserDao.*(..))
execution(* cn.itcast.spring3.demo1.*(..))
execution(* cn.itcast.spring3.demo1..*(..))
execution(* cn.itcast.dao.UserDAO+.*(..))
aspectJ的开发需要依赖aop的环境.
引入aspectJ的jar包:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
引入spring整合aspectJ的jar包:spring-aspects-3.2.0.RELEASE.jar
Log4j和spring的配置文件
cn.green.demo5
UserDao
UserDaoImpl
切面:就是切点和通知组合.
在哪些类的哪些方法上使用增强.
定义切面:
@Aspect
定义增强:
@Before 前置通知,相当于BeforeAdvice
@AfterReturning 后置通知,相当于AfterReturningAdvice
@Around 环绕通知,相当于MethodInterceptor
@AfterThrowing抛出通知,相当于ThrowAdvice
@After 最终final通知,不管是否异常,该通知都会执行
@DeclareParents 引介通知,相当于IntroductionInterceptor (不要求掌握)
代码:
package cn.green.demo5;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class MyAspectAnno {
@Before(value="execution(* cn.green.demo5.UserDao.add(..))")
public void before(){
System.out.println("这是before增强.....");
}
}
引入aop的约束
xml version="1.0" encoding="UTF-8"?>
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">
/>
id="userDao" class="cn.green.demo5.UserDaoImpl">
id="myAspectionAnno" class="cn.green.demo5.MyAspectAnno">
package cn.green.demo5;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class TestCase{
@Resource(name="userDao")
private UserDao userDao;
@Test
public void demo(){
userDao.delete();
userDao.update();
userDao.add();
userDao.find();
}
}
delete run....
update run....
这是before增强.....
add run....
find run....
@Before:前置通知:在目标方法之前执行.(不能拦截目标方法.)
* JoinPoint:连接点
@AfterReturing:后置通知:在目标方法执行之后执行.
* JoinPoint:连接点
* Object:返回值
// 后置增强:
@AfterReturning(value="execution(* cn.itcast.spring3.demo1.UserDao.delete(..))",returning="result")
public void afterReturing(JoinPoint joinPoint,Object result){
System.out.println("后置增强=============="+result);
}
@Around:环绕通知:
// 环绕通知:(阻止目标对象的方法执行)
@Around(value="execution(* cn.itcast.spring3.demo1.UserDao.find(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕前增强=============");
Object obj = joinPoint.proceed();
System.out.println("环绕后增强=============");
return obj;
}
@AfterThrowing:抛出异常通知:
// 抛出异常通知:
@AfterThrowing(value="execution(* cn.itcast.spring3.demo1.UserDao.find(..))",throwing="e")
public void afterThrowing(Throwable e){
System.out.println("异常通知========="+e.getMessage());
}
@After:最终通知.类似finally代码块.
// 最终通知:
@After(value="execution(* cn.itcast.spring3.demo1.UserDao.find(..))")
public void after(){
System.out.println("最终通知===========");
}
// 定义一个切点:
@Pointcut(value="execution(* cn.itcast.spring3.demo1.UserDao.find(..))")
private void mypointcut(){}
面试题:
Advisor 和 Aspect区别?
Advisor:是Spring传统AOP开发中提供一个切面概念.一般情况下都一个切入点和一个通知组合.
Aspect:是真正意义上的切面,可以有多个切入点和多个通知组合.
aspectJ的开发需要依赖aop的环境.
引入aspectJ的jar包:com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
引入spring整合aspectJ的jar包:spring-aspects-3.2.0.RELEASE.jar
Log4j和spring的配置文件
cn.spring3.demo2
OrderDao
public class MyAspectXml {
public void before(){
System.out.println("前置增强============");
}
}
id="orderDao" class="cn.spring3.demo2.OrderDao">
id="myAspect" class="cn.spring3.demo2.MyAspectXml">
expression="execution(* cn.spring3.demo2.OrderDao.add(..))" id="mypointcut"/>
ref="myAspect">
method="before" pointcut-ref="mypointcut"/>
expression="execution(* cn.spring3.demo2.OrderDao.add(..))" id="mypointcut1"/>
expression="execution(* cn.spring3.demo2.OrderDao.delete(..))" id="mypointcut2"/>
ref="myAspect">
method="after" pointcut-ref="mypointcut1"/>
method="afterThrowing" pointcut-ref="mypointcut1" throwing="e"/>
method="afterReturing" pointcut-ref="mypointcut2" returning="result"/>