Spring中的AOP

一、Spring注解

注解名称 解释
@Component 实例化Bean,默认名称为类名收字母变小写。支持自定义名称
@Repository @Component子标签。作用和@Component一样。用在持久层
@Service @Component子标签。作用和@Component一样。用在业务层
@Controller @Component子标签。作用和@Component一样。用在控制器层
@Configuration @Component子标签。作用和@Component一样。用配置类
@Autowired 自动注入。默认byType,如果多个同类型bean,使用byName(默认通过属性名查找是否有同名的bean,也可以通过@Qualifier("bean名称"),执行需要注入的Bean名称)
@Resource 非Spring注解。默认byName,如果没找到,使用byType。        

使用方式

(1)在applicationContext.xml(Spring的xml文件)中的头文件中添加xmlns:context的xsd规范。

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
">

(2)在该文件中配置希望被扫描的包


(3)在想要的类上添加注解,相当与,可以在定义名称

@Component

(4)在想要注入的属性添加注解

@Autowired

二、Spring整合Test模块

普通测试使用

(1)导入junit依赖


  junit
  junit
  4.13.2
  test

(2)写一个随意名称的public void 修饰并且空参的方法,并添加@Test注解

Spring整合Test

(1)导入spring-test依赖


    org.springframework
    spring-test
    5.3.23
    test

(2)给测试类添加注解

// 使用Spring整合Junit4的类启动当前测试类
@RunWith(SpringJUnit4ClassRunner.class)
// 启动时加载的配置文件,里面要包含classpath
@ContextConfiguration(locations = "classpath:applicatonContext.xml")

三、Spring的AOP

(1)AOP作用:在不修改原有代码的基础上,对方法的功能进行扩充。

(2)相关概念:

        Aspect:切面。即join point + Advice

        join point: 切入点。就是我们平时说的目标方法,或说对哪个方法做扩展,做增强。

        Advice:通知,增强内容。

        Pointcut:切点。就是表达式,通过表达式说明哪些方法是join point

        AOP Proxy:代理。Spring支持JDK动态代理和cglib动态代理两种方式,可以通过proxy-target-class=true把默认的JDK动态代理修改为Cglib动态代理。

        Weaving:织入。织入就是把Advice添加到join point的过程。

(3)在Spring中提供了两种方式实现AOP:

  • Schema-based:  所有的通知都需要实现特定类型的接口。

  • AspectJ:可以使用普通Java类结合特定的配置标签实现通知。

 四、Schema-based方式实现AOP

(1)通知分类

  • 前置通知:在切入点之前执行的增强功能。通知需要实现MethodBeforeAdvice接口

  • 后置通知:在切入点之后执行的增强功能。通知需要实现AfterReturningAdvice接口

  • 环绕通知:一个方法包含了前置通知和后置通知的功能。通知需要实现MethodInterceptor接口

  • 异常通知:如果切入点中出现了异常(绝对不能try...catch解决了异常)就会触发异常通知。通知需要实现ThrowsAdvice接口。

 (2)使用方式

        1.导入aspectjweaver依赖


    org.aspectj
    aspectjweaver
    1.9.9.1

        2.定义通知类并实现相应的接口,并重写方法

package com.bjsxt.aop;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class MyBefore implements MethodBeforeAdvice {
    /**
     * @param method 切入点 目标方法
     * @param args 切入点的参数
     * @param target 切入点所在的类对象
     * @throws Throwable
     */
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置通知执行了");
    }
}

        3.将切入点类和通知类放到spring容器中,并将切入点类设置到切点中,最后将通知类织入到切入点中。




    
    

    
        
        
        
        
    

        4.其他通知使用方法类似。

                特殊的有

                1.环绕通知的参数为 MethodInvocation invocation 可以通过该参数调用切入点方法,invocation.proceed();

                2.异常通知的接口中没有需要重写的方法但是必须写一个

                 public void afterThrowing(Exception e){}的类,返回值可以改变,其他的不能改变。

五、AspectJ实现AOP

(1)创建通知类

package com.bjsxt.advice;

import org.aspectj.lang.ProceedingJoinPoint;

public class MyAdvice {
    //前置通知方法
        public void before(){
            System.out.println("我是前置通知方法...");
        }
    //后置通知方法
        public void after(){
            System.out.println("我是后置通知方法...");
        }
    //环绕通知方法
        public Object round(ProceedingJoinPoint pp) throws Throwable {
            System.out.println("环绕---前");
            //放行
            Object proceed = pp.proceed();

            System.out.println("环绕---后");
            return proceed;
        }
    //异常通知方法
        public  void  myThrow(Exception ex){
            System.out.println("我是异常通知......"+ex.getMessage());
        }
}

(2)配置AOP



    
    
    
    
    
    
        
        
            
            
            
            
            
            
            
            
            
            
            		             
        
    

(3)有参数的配置




    

    

    
        
        
            
            
            
            
            
            
            
            
			
            
        
    

六、注解方式实现AOP

(1)在spring容器文件中让AOP注解生效

   
   

(2)@Aspect

作用:声明该类为通知类

使用:结合@Component在通知类上使用

(3)@Pointcut("execution(* com.bjsxt.service.impl.UserServiceImpl.testMethod())")

作用:声明切点

使用:在切点方法上使用

(4)通知织入

@Before("com.bjsxt.service.impl.UserServiceImpl.testMethod()")

作用:声明方法为前置通知方法

使用:在前置通知方法上声明

@After

@AfterReturning("com.bjsxt.service.impl.UserServiceImpl.testMethod()")

作用:声明方法为后置通知方法

使用:在后置通知方法上声明

@Around

@Around("com.bjsxt.service.impl.UserServiceImpl.testMethod()")

作用:声明方法为环绕通知方法

使用:在环绕通知方法上声明

@AfterThrowing

@AfterThrowing(value = "com.bjsxt.service.impl.UserServiceImpl.testMethod()",throwing = "e")

作用:声明方法为异常通知方法

使用:在异常通知方法上声明

七、代理设计模式

(1)静态代理:代理对象由程序员自己编写!

(2)动态代理: 代理对象是动态生产的!动态代理又分为JDK动态代理和Cglib动态代理两种实现方式。其中JDK动态代理是基于接口实现,也就是代理对象和真实对象需要实现相同的接口,JDK动态代理是Java官方提供的技术。Cglib动态代理是基于继承实现的,也就是代理对象需要继承真实对象,Cglib动态代理是第三方的技术,使用的时候需要导入jar包。

JDK的动态代理,基于反射

package com.bjsxt.adv;

public interface Service {
    void test();
}

被代理类 

package com.bjsxt.adv.impl;

import com.bjsxt.adv.Service;

public class ServiceImpl implements Service {
    @Override
    public void test() {
        System.out.println("test");
    }
}

代理类 

package com.bjsxt.adv;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyAdvice implements InvocationHandler {
    public Object object;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("动态代理前置");
        Object invoke = method.invoke(object, args);
        System.out.println("动态代理后置");
        return invoke;
    }
}

使用类 

package com.bjsxt.adv.impl;

import com.bjsxt.adv.MyAdvice;
import com.bjsxt.adv.Service;

import java.lang.reflect.Proxy;

public class Test {
    public static void main(String[] args) {
        MyAdvice myAdvice = new MyAdvice();
        myAdvice.object = new ServiceImpl();
        Service service = (Service) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{Service.class}, myAdvice);
        service.test();

    }
}

cglib的动态代理,基于继承

package com.bjsxt.cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxy implements MethodInterceptor {
    @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;
    }
}
package com.bjsxt.cglib;

import com.bjsxt.adv.impl.ServiceImpl;
import net.sf.cglib.proxy.Enhancer;

public class CglibTest {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setCallback(new CglibProxy());
        enhancer.setSuperclass(ServiceImpl.class);

        ServiceImpl service = (ServiceImpl) enhancer.create();
        service.test();
    }
}

你可能感兴趣的:(spring,java,后端)