1.面向切面的编程
Advice(通知|额外功能|附加操作):除了目标方法以外的操作都成为通知 事务 日志 性能
pointCut(切入点):用来告诉你项目中那些类中那些方法需要加入通知
Aspect(切面): Advice(通知) + pointCut(切入点)
Aop : Aspect Oriented programming 面向切面的编程
2.Aop的编程思路
1.引入Aop相关jar
Spring-aop
Spring-expression
Spring-aspects
2.开发通知类
MethodBeforeAdvice 前置通知
AfterReturningAdvice 后置通知
ThrowsAdvice 异常通知
MethodInterceptor 环绕通知
//参数1:当前执行方法对象
//参数2:当前执行方法参数
//参数3:目标对象
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("===================前置对象=============");
System.out.println("方法名:"+method.getName());
}
3.工厂通知管理
<!--管理通知-->
<bean class="beforeAop.MyAdvice" id="myAdvice"></bean>
4.配置切面
<!--配置切面-->
<aop:config>
<!--配置切入点 id:切入点在工厂中唯一标识-->
<aop:pointcut id="pc" expression="execution(* beforeAop.EmpServiceImp.*(..))"/>
<!--注:第一个*代表返回值任意,第二个*代表任意方法,(..)代表任意参数-->
<!--配置切入面-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="pc"></aop:advisor>
</aop:config>
- 启动工厂测试
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beforeAop/Spring.xml");
EmpService empService = (EmpService) context.getBean("empService");
//注意:由于切面的存在获取的不再是原始的目标对象而是程序动态生成的代理对象
System.out.println(empService.getClass());
empService.save("小黑");
3.环绕通知的开发
1.引入jar
Spring-aop
Spring-expression
Spring-aspects
2.开发环绕通知
类 implements MethodInterceptor{
}
ublic class Huanrao implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("方法对象:"+methodInvocation.getMethod().getName());
System.out.println("方法参数:"+methodInvocation.getArguments()[0]);
System.out.println("目标对象:"+methodInvocation.getThis());
long start = new Date().getTime();
System.out.println("进入环绕通知记录起始时间:"+start);
Object proceed = methodInvocation.proceed();
long end = new Date().getTime();
System.out.println("目标方法执行结束的时间:"+end);
System.out.println("本次业务执行耗费的总时间:"+(end-start));
return null;
}
3.管理通知类
<!--管理环绕通知-->
<bean class="huanrao.Huanrao" id="huanrao"></bean>
4.配置切面
<!--配置切面-->
<aop:config>
<aop:pointcut id="pc" expression="execution(* huanrao.EmpServiceImp.*(..))"></aop:pointcut>
<aop:advisor advice-ref="huanrao" pointcut-ref="pc"></aop:advisor>
</aop:config>
5.启动工厂测试
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("huanrao/Spring.xml");
EmpService empService = (EmpService) context.getBean("empService");
empService.save("小强");
6.总结
-
现有业务层中存在问题?
问题:在现有业务层开发中控制事务的代码存在大量冗余 -
代理 Proxy
a.什么是代理?
代理是java设计模式
b.代理作用
代理对象保证原始功能不变 从而进一步增加额外功能 -
能不能使用代理对象解决现有业务层问题?
解决方案:
a.将控制事务代码交给代理执行
b.业务层只专注于业务逻辑对象 -
静态代理对象开发?
什么是静态代理对象:为现有业务层组件手动开发一个代理对象的过程
代理对象开发原则:代理对象和业务逻辑实现相同接口 代理对象中一定依赖于业务逻辑对象(目标对象)
静态代理对象存在问题:往往在开发我们书写的不仅仅是一两个业务层,业务量太大。 -
为了解决静态代理存在问题-====>动态代理
动态代理:在程序运行的过程中动态为项目中某些对象创建代理对象的过程
Object proxy=Proxy.newProxyInstance(当前线程类加载,创建代理对象的接口类型InvocationHanlder invoke方法,);
porxy.方法 -
Aop面向切面的编程
通知Advice:除了目标方法以外的操作都称之为通知|额外功能|附加操作
切入点pointcut:指定项目中通知应用于项目中那些类中那些方法
切面:Aspect: 通知(前置|后置|环绕|异常)+切入点 -
切入点表达式
方法级别切入点表达式:execution(返回值类型 包.类名 .方法名(参数类型));
类级别切入点表达式:within(包.类名)
1.execution表达式===============>方法级别切入点表达式语法: execution(访问权限修饰符 返回值类型 包名.类名.方法名(参数类型)) execution(返回值类型 包名.类名.方法名(参数类型)) 通配符: * 任意 ..任意(只能用在参数类型) a. execution(* com.baizhi.service.*.*(..)) 返回值: 任意类型 包 : com.baizhi.service 类 : 任意类 方法 : 任意方法 参数 : 任意参数 b. execution(* com.baizhi.service.*ServiceImpl.save*(String)) 返回值: 任意返回值类型 包 : com.baizhi.service 类 : 以ServiceImpl结尾类 方法 : 以save开头方法名 参数 : 且只有一个参数参数类型必须为String类型 c. execution(String com.baizhi.service.*Service*.*(String,String)) 返回值: 必须是String类型返回值 包 : com.baizhi.service 类 : 类名包含Service的类 方法 : 任意 参数 : 类中必须含有两个参数的方法,且参数的类型必须都为String类型 d. execution(* com.baizhi.service..*ServiceImpl.*(String)) 返回值: 任意类型 包 : com.baizhi.service包以及com.baizhi.service包子包 类 : 以ServiceImpl结尾类 方法 : 任意方法 参数 : 参数带一个String类型的参数 e. execution(* com.baizhi.service.*.*(..)) 重点 返回值: 任意 包 : com.baizhi.service 类 : 任意 方法 : 任意 参数 : 任意 f. execution(* com.baizhi.service..*.*(..)) 重点 返回值: 任意 包 : com.baizhi.service包以及子包 类 : 任意 方法 : 任意 参数 : 任意 g. execution(* *.*(..)) 项目中所有类中所有方法全部切入 注意: 这种写法可能会出现问题 原则: 一般在使用AOP编程时多数会切入项目中业务组件对象 一定要精准切入避免不必要的切入
2.within表达式
语法: within(包.类名) ======> 类级别切入点表达式
注意: 如果通知要被业务组件中所有方法使用不推荐使用execution表达式 推荐使用 within表达式 -
多个切面的执行顺序
1.多个aop切面的执行顺序默认是配置顺序
2.在标签<aop:advisor advice-ref point-ref order=""/>
order int 整数 0 1 2 3 4… 数字越小优先执行 一旦执行order属性 配置顺序失效 order值相同,配置顺序优先
9. Spring框架中有几种创建代理对象的方式?分别是什么?有什么区别(面试题)
2 种
jdk : 提供Proxy 根据接口生成代理对象 默认使用jdk中proxy
Spring : 提供CGLIB 根据实现类生成代理对象
修改Spring 框架默认代理对象为CGLIB:
<aop:config proxy-target-class=“false(proxy)|true(CGLIB)”>