1. Aop—–面向切面编程:原理动态代理
1、 aop在spring中的作用
a) 提供声明式事务
b) 允许用户自定义切面,在不改变原有功能的前提下,添加新的功能。
2、 名词解释
a) 关注点:增加的某个业务。如添加日志,事务等功能。
b) 切面(aspect)一个关注点的模块化。
c) 通知(advice)在切面的某个特定的连接点上执行的动作。
d) 织入:把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。
3、 常用通知类型
a) 前置通知:MethodBeforeAdvice
b) 后置通知:AfterReturningAdvice
c) 环绕通知:MethodInterceptor
d) 异常通知:ThrowsAdvice,通常使用pojo方式来实现!
4、 spring提供实现aop的两种方式:
a) 依赖接口方式
i. 第一步导入aop相应的jar包。
ii. 定义一个接口
iii. 添加配置文件:配置文件要添加aop的命名空间
iv. 添加aop标签:使用<aop:config>
v. 因为aop实现原理是动态代理:
Exception in thread “main” org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named ‘userDao’ must be of type [com.bjsxt.dao.impl.UserDaoImpl], but was actually of type [com.sun.proxy.$Proxy2] |
vi. 前置通知
public class Before implements MethodBeforeAdvice {
/** * method:方法名 * args:参数列表 * target:目标对象 */ @Override public void before(Method method, Object[] args, Object target) throws Throwable { if (args.length!=0) { for (int i = 0; i < args.length; i++) { System.out.println(method + “\t” + args[i] +“\t” + target.toString()+“\t”); } } System.out.println(method + “\t” + args +“\t” + target.toString()+“\t”); System.out.println(“前置通知!”); } } <!– 要实现调dao层的方法就会打印出前置通知! –> <bean id=“userDao” class=“com.bjsxt.dao.impl.UserDaoImpl”></bean>
<!– 定义前置通知 –> <bean id=“before” class=“com.bjsxt.advice.Before”></bean> <!– aop的配置 –> <aop:config> <!– 切入点: 第一个*号表示任意返回类型 第一个*后面代表包的路径 第二个*代表包内的任意类 第三个*代表保内的任意方法 (..):代表方法中的任意参数
–> <aop:pointcut expression=“execution(* com.bjsxt.dao.impl.*.*(..))” id=“mypoint”/> <!– advice-ref:指的是配置那个通知 pointcut–ref:切入点的Id –> <aop:advisor advice-ref=“before” pointcut-ref=“mypoint”/> </aop:config> </beans> |
vii. 测试:
public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext(“spring.xml”); UserDao daoImpl = ac.getBean(“userDao”,UserDao.class); daoImpl.delete(12); daoImpl.add(); } 注意该地方使用的是UserDao接口 |
viii. 后置通知
public class After implements AfterReturningAdvice{ /** * returnValue:返回值 * method:方法名 * args:参数列表 * target:目标对象 */ @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println(returnValue); System.out.println(“后置通知!”); } } <!– aop的配置 –> <aop:config> <aop:pointcut expression=“execution(* com.bjsxt.dao.impl.*.*(..))” id=“mypoint”/> <!– advice-ref:指的是配置那个通知 pointcut–ref:切入点的Id –> <aop:advisor advice-ref=“before” pointcut-ref=“mypoint”/> <aop:advisor advice-ref=“after” pointcut-ref=“mypoint”/> </aop:config> |
ix. 环绕通知:环绕通知-类似于前置通知,后置通知。 环绕通知的功能,相当于前置通知+后置通知!在实际开发过程中:要不采用环绕通知,要不采用前置通知+后置通知。
b) Pojo方式(AspectJ)
i. 先创建一个类:
public class Log { public void before(){ System.out.println(“方法执行前”); }
public void after(){ System.out.println(“方法执行后!”); }
public void ex(Exception e) throws Exception{ System.out.println(“异常通知!”+e.getMessage()); }
public Object around(ProceedingJoinPoint p) throws Throwable{ System.out.println(“环绕通知前!”); Object obj = p.proceed(); System.out.println(“环绕通知后!”); return obj; } } |
ii. Spring.xml
<!– 使用pojo方式来实现aop –> <bean id=“log” class=“com.bjsxt.advice.Log”></bean> <aop:config> <aop:pointcut expression=”execution(* com.bjsxt.dao.impl.*.*(..))” id=”mypoint“/> <aop:aspect ref=”log”> <aop:before method=”before” pointcut–ref=”mypoint“/> <aop:after method=”after” pointcut–ref=”mypoint“/> <aop:around method=”around” pointcut–ref=”mypoint“/> <aop:after-throwing method=”ex” pointcut-ref=”mypoint” throwing=”e”/> </aop:aspect> </aop:config> |
c) 注解方式实现aop
@Aspect public class Logs { @Before(“execution(* com.bjsxt.dao.impl.*.*(..))”) public void before(){ System.out.println(“方法执行前!”); } @After(“execution(* com.bjsxt.dao.impl.*.*(..))”) public void after(){ System.out.println(“方法执行后”); } @Around(“execution(* com.bjsxt.dao.impl.*.*(..))”) public Object around(ProceedingJoinPoint p) throws Throwable{ System.out.println(“环绕通知前!”); Object obj = p.proceed(); System.out.println(“环绕通知后!”); return obj; } } |
d) Spring.xml
<!– 使用注解方式来实现aop –> <bean id=“logs” class=“com.bjsxt.advice.Logs”></bean> <!– aop的配置 –> <aop:aspectj-autoproxy/> |