Spring AOP详解及配置


aop:(Aspect Oriented Programming)面向切面编程,纵向重复,横向抽取

 

代理: 生活中的实例:找明星拍戏,上综艺。拍戏   直接找明星,说明明星太小。如果明星有点名气,那就不能直接访问了,必须先通过先访问明星的经纪人,然后由经纪人访问明星,经纪人就是明星的代理。放在程序当中,有一个目标对象,一个代理对象, 你想访问目标对象,必须访问代理对象,由代理对象决定访问目标对象。Java 中提供了一个类Proxy 能够实现代理

   Spring AOP

     利用了代理技术  主要应用于在service层的事务管理

 

Spring实现aop 有两种方法

(1)动态代理(建议):被代理对象必须实现接口,如果没有接口则不能实现动态代理

(2)cglib代理: 第三方的代理技术。任何类都可以实现代理,使用继承的机制实现代理,所以被代理对象不能被final修饰

   

   手动实现 动态代理

 

   准备一个UserService UserServiceImpl

   准备获得UserService代理对象的类

1. 获取代理对象  通过调用Proxy 的new ProxyInstance方法 创第三个参数(1本类的加载器,2代理对象的接口(实现类获得接口),3this),这样就得到了一个代理对象

2. 实现代理对象的方法 让这个类 实现InvocationHandler接口 实现了它的方法 invoke(代理的对象,调用的方法,方法的的参数)

被代理的对象方法还是要被调用,所有调用method,invoke()两个参数,一个是被代理的对象,参数 给该类加上一个属性被代理对象,并给该类添加构造函数,在调用被代理对象方法的前后 可以加上对应的内容

public class UserServiceProxyFactory implements InvocationHandler{
   private UserService userService;

    public UserServiceProxyFactory(UserService userService) {
        this.userService = userService;
    }

    public UserService getUserServiceProxy(){
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(UserServiceProxyFactory.class.getClassLoader(),
                UserServiceImpl.class.getInterfaces(), this);
        return userServiceProxy; //用户服务代理
    
}

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开启事务");
        //调用了代理对象(UserService)的方法
        
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 配置

   

   7个专业名词

   

   JoinPoint (连接点)

   

   

1. 导包

4+2  +  2+2  springaop aspect) spring依赖包()

2. 准备目标对象 UserServiceImpl

3. 准备通知

4. 配置applicationContext.xml文件

导入约束:

直接打入<aop:conf 如果有提示 直接打回车 自动帮你导入约束

没有的话  就手动导入

xmlns:aop="http://www.springframework.org/schema/aop"

http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd

<!--配置aop切入-->
       
<aop:config>
           
       </aop:config>

 

配置切入:

1. 配置切入点

<aop:pointcut id=”” expreession=”” 目标对象要增强的方法</aop:pointcut>

 

2. 配置切面: 将通知织入到对应的切入点

<aop:aspect ref="通知">
</aop:aspect>

  多种方式切入

总共有五种切入方式

1. 在目标对象方法前调用

<aop:before method="before" pointcut-ref="pc"></aop:before>

 

2. 在目标对象方法后调用(没有异常,有异常不调用)

<aop:after-returning method="afterReturning" pointcut-ref="pc"></aop:after-returning>

 

3. 在目标对象方法后(不管啊有无异常)

<aop:after method="after" pointcut-ref="pc"></aop:after>

 

4. 在目标对象方法前后调用代码(特殊,在通知中的方法)

ProceedingJoinPoint(参数)如果有异常方法后不调用

<aop:around method="around" pointcut-ref="pc"></aop:around>

5. 只在目标对象方法出现异常时调用

<aop:after-throwing method="throwException" pointcut-ref="pc"></aop:after-throwing>

 

 <!--引入切入点 写那个类中的方法代码块-->
    
<aop:before method="通知中增强的代码pointcut-ref="切入点"></aop:before>

  

实现代码:

<aop:config>
    <!--配置切入点

      proxy-target-class="true"  基于类的代理将起作用 
       proxy-target-class="false"     基于接口的代理将起作用
   如果目标对象没有实现接口,则默认会采用CGLIB代理; 
 如果目标对象实现了接口,可以强制使用CGLIB实现代理。

-->
    <!--
        public void cn.hd.springProxy.impl.UserServiceImpl.add()
                *  cn.hd.springProxy.impl.UserServiceImpl.add() //public可以省略  返回值可以是是任意类型*号代替
                *  cn.hd.springProxy.impl.*ServiceImpl.*(..)
                //所有方法可以用 * 所有参数可以用.. 所有Service  可以 *ServiceImpl
                *  cn.hd.springProxy.impl..*ServiceImpl.*(..)
    -->
    <aop:pointcut id="pc" expression="execution(* cn.hd.springProxy.impl.*ServiceImpl.*(..))"></aop:pointcut>
    <!--配置切面 织入通知-->
    <aop:aspect ref="myAdvice">
        <!--引入切入点 写那个类中的方法代码块-->
        <aop:before method="before" pointcut-ref="pc"></aop:before>
    </aop:aspect>
</aop:config>

   

使用注解的方式配置AOP(了解)

1. 开启注解模式

<!--开启注解模式-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

 

2. 注解切面

再通知上面加上一个注解 @ Aspect

 

  再通知的方法上面加上切点

  五种:

 @Before(表达式) @After @AfterReturning @Around @AfterThrowing

@Before("execution(* cn.hd.springProxyAnnotation.impl.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("在目标对象方法前调用");
    }

 书写表达方式有两种

1. 直接写

@Before("execution(* cn.hd.springProxyAnnotation.impl.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("在目标对象方法前调用");
    }

 

2. 配置一个切点 调用类的方法获得切点

public class MyAdvice {
@Pointcut("execution(* cn.hd.springProxyAnnotation.impl.UserServiceImpl.*(..))")
    public void pc(){ }

}

@AfterReturning("MyAdvice.pc()")
public void afterReturning(){
    System.out.println("如果目标对象方法吗没有出现异常"+
            "就会在该方法调用后调用");
}

猜你喜欢

转载自blog.csdn.net/zyz0225/article/details/80917197