Spring aop
Aop:面向切面编程,纵向重复,横向抽取
代理:生活中的例子:找明星拍戏。上综艺,唱歌,直接找明星说明这个明星太小了。如果明星有点名气,那就不直接访问了,
必须先同过访问明星的经纪人,然后经纪人访问明星。放在程序当中,有一个目标对象有一个代理对象。你想要访问目标对象,必须先通过代理对象访问目标对象。Java提供了一个类proxy能实现代理。
Spring AOP
利用了代理技术 解决主要用于service层的事务管理
Spring 实现aop有两种方法:
(1)动态代理
被代理对象必须有接口,如果没有接口咋不能实现动态
(2)cglib代理:
第三方的代理计技术。任何类都可以实现代理,使用继承的机制实现代理,所以被代理不能被final修饰。
手动实现动态代理:
准备一个UserService UserServiceImpl
准备一个获得UserService代理对象的类
1.获得代理对象 通过调用proxy的newProxyInstance方法 传递三个参数
①本类的加载器 ②代理对象的接口(实现获得的接口)③this. 这样就得到一个代理对象
2.实现代理对象的方法,让这个类 实现Invocation接口 实现他的方法invoke(代理对象,调用的方法,方法的参数)
3.被代理对象还要被调用,所有调用metho.invoke()两个参数,一个是被代理的对象,参数 是给该类加上一个属性被代理对象,并给该类添加构造函数。在调用被代理对象前后,可以加上对象的内容
public class UserServiceProxyFactory implements InvocationHandler {
private UserService userService;
public UserServiceProxyFactory(UserService userService) {
this.userService = userService;
}
public UserService getUserServiceProxy() {
/*getClassLoader()类加载器,getInterfaces() 得到代理对象*/
UserService userServiceProxy = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(), UserServiceImpl.class.getInterfaces(), this);
return userServiceProxy;
}
@Override
/*proxp:代理对象
参数:被代理的对象,被代理的方法,参数
*
* */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开启事务");
/*调用被代理对象的方法*/
Object invoke = method.invoke(userService, args);
System.out.println("提交事务");
return invoke;
}
}
cglib代理
public class UserServiceProxyFactory2 implements MethodInterceptor{
public UserService getUserServiceProxy() {
/*帮助我们生成代理对象 */
Enhancer enhancer=new Enhancer();
/*设置对谁进行代理*/
enhancer.setSuperclass(UserServiceImpl.class);
/*设置回调方法*/
enhancer.setCallback(this);
UserService userServiceProxy = (UserService) enhancer.create();
return userServiceProxy;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("开启事务");
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("关闭事务");
return o1;
}
}
Spring AOP配置
1.导包(4+2 +2+2 spring(aop aspect) spring依赖包())
2.准备目标对象 userServiceImpl
3.准备通知
4.配置applicatContext.xml文件
导入约束:
直接打入<aop:Conf 如果有提示 直接回车 自动帮你导 没有提示的话就手动导入>
配置切入:
<aop:pointcut id="pc" expression="execution(目标对象要增强的方法) "></aop:pointcut>
配置切面:将通知织入到对应的切入点
<aop:aspect ref="方法">
多种方式切入:
总共有五种切入方式
①在目标方法前调用
Aop:before
②在目标对方法后调用
Aop:afterReruming
③在目标对象方法后调用(不管有没有异常)
aop:after
④在目标对象前后调用代码(特殊,在通知中的方法proceedingJoinPoint参数)如果有异常后方法不 调用
Aop:around
⑤只在目标方法出现异常时调用
Aop:after-thoreing
<aop:before methor="通知增强的方法" pointcut-ref="切入点"><aop:before/>
<aop:config>
<!--配置切入点-->
<!-- public void cn.hd.SpringProxy.impl.UserServiceImpl.add()
省略 返回值* cn.hd.SpringProxy.impl.UserServiceImpl.add()
cn.hd.SpringProxy.impl.UserServiceImpl.*(..) //所有方法可以用*代替所有参数用
cn.hd.SpringProxy.impl.*ServiceImpl.*(..)
-->
<aop:pointcut id="pc" expression="execution(* cn.hd.SpringProxy.impl..*UserServiceImpl.*(..))"></aop:pointcut>
<!--配置切面 植入通知-->
<aop:aspect ref="myAdvice">
<!-- <aop:before method="after" pointcut-ref="pc"></aop:before>-->
<!-- <aop:after method="after" pointcut-ref="pc"></aop:after>-->
<!--环绕调用 如果有异常 则不调用围绕后的方法-->
<!-- <aop:around method="around" pointcut-ref="pc"></aop:around>-->
<!--出了一场就不调用-->
<!-- <aop:after-returning method="afterReturning" pointcut-ref="pc"></aop:after-returning>
-->
<!--出现异常了才调用-->
<aop:after-throwing method="throwException" pointcut-ref="pc"></aop:after-throwing>
</aop:aspect>
使用注解的方式配置AOP(了解)
1.开启注解模式:
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2.注解切面
在通知上面加上一个注解
@Component("myAdvice")
@Aspect
public class MyAdvice {
再通知的方法上面加上切点
五种
@Before(表达式) @After @AfterReturning @Around @AfterThrowing
@Before("MyAdvice.pc()")
public void before(){
System.out.println("在目标方法前调用");
}
①直接写
②配置一个切点,调用类的方法获得的切点
@Pointcut("execution(* cn.hd.springProxyAnnoation.impl.UserServiceImpl.*(..))")
public void pc(){
}
@Before("MyAdvice.pc()")
public void before(){
System.out.println("在目标方法前调用");
}