IOC和AOP的理解

面试题:1、谈谈你对IOC和AOP的理解

参考资料:
尝试讲清楚spring核心概念IOC和AOP
Spring JdbcTemplate详解
Java之JDBC
【Spring基础】AOP使用注解实战

答:IOC是spring的一个容器,可以帮助我们创建对象,而不需要我们手动去创建。IOC有一个强大的功能依赖注入(DI),可以通过依赖注入更好的去管理Bean,达到解耦的目的。举个例子:我们用的JDBCTemplate可以通过xml的方式配置,然后去注入使用,但是需要数据源,我们可以随意切换数据源,使得JDBCTemplate不强制依赖某一数据源,达到解耦。

答:AOP常常用在事务和日志中,因为他可以不植入代码中执行,

2、IOC的过程给讲讲;还有B+Tree的指针有利于范围查找;zookeeper和eureka和区别,一个是http,一个是RPC。

3、Aop中可以改变目标方法的参数吗?

一、IOC(设计模式:工厂模式)

1.1、概念:是一个spring的容器,帮助我们创建对象

二、Aop概念

Aop是一个概念,springAop和aspectJ是Aop的实现。如果说前端发送过来请求到controller再到service再到dao是由上而下的话,那么springAop是从水平切入,但是和其是充分解耦的,从而实现一些功能,比如日志,事务,异常,权限等。 实现切面的一些功能。比如日志,事务,权限,异常等。

三、Aop和aspectJ的联系

Aop的语法比较复杂,所以借助了aspectJ的语法风格,但是底层还是自己实现的。

四、Aop的使用

4.1、开启Aop

通过@Configuration注解来开启支持aspectJ,并且加注解@EnableAspectJAutoProxy。
@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
    
    


}

4.2、声明一个Aspect(切面)类

声明一个Aspect注释类,并且把该类定义成一个Bean交给spring管理。

4.2.1、切面类包含通知和切入点

@Component
@Aspect
public class AspectTest {
    
    

}

4.3、在切面类编写切入点和通知

4.3.1、切入点就是在哪些目标方法将要进行执行通知

4.3.2、通知就是围绕目标方法执行的方法

4.3.4、代码如下:(可以发现切入点表达式都是一样,我怎么去消除呢?)

@Component
@Aspect
public class AspectTest {
    
    


    @Before("execution(* com.xuecheng.aop.service..*.*(..))")
    public void before() {
    
    
        System.out.println("before执行。。。。");
    }

    @After("execution(* com.xuecheng.aop.service..*.*(..))")
    public void after() {
    
    
        System.out.println("after执行。。。。");
    }

}

4.3.5、优化后的代码如下:


@Component
@Aspect
public class AspectTest {
    
    
    
    @Pointcut("execution(* com.xuecheng.aop.service..*.*(..))")
    public void pointCut() {
    
    

    }


    @Before("pointCut()")
    public void before(){
    
    
        System.out.println("before执行。。。。");
    }

    @After("pointCut()")
    public void after(){
    
    
        System.out.println("after执行。。。。");
    }



}

4.4、编写目标方法

4.4.1、接口代码

public interface FatherServ {
    
    

    public void ss();
}

4.4.2、实现类(目标类)代码

@Component("s")
public class TestService implements FatherServ {
    
    
    public void ss(){
    
    
        System.out.println("目标方法执行...");
    }
}

4.5、测试结果如下:

before执行。。。。
目标方法执行...
after执行。。。。

五、Aop中的切入点表达式分析

参考资料:Spring AOP切点表达式详解

在这里插入图片描述

在执行表达式的时候,我们可以通过逻辑运算符&&(and) , ||(or) , !(not)对表达式进行搭配。比如:

execution(* com.jpeony.spring.ConferenceServiceImpl.conference(..)
       && within(com.jpeony.spring.*))

增加了一个限制就是我们只管com.jpeony.spring下的包,这里的&&可以使用and来替代,
同理|| , !都是一样的用法,灵活多变,只能根据实际情况看着办。

5.1、execution(粒度可以精确到具体的方法)

5.2、within(粒度只能精确到类)

5.2.1、精确到BusinessObject类,进行该类下的所有方法增强。

within(com.spring.service.BusinessObject)

5.2.2、精确到service包下的所有类,但是不包括子包下的类

within(com.spring.service.*)

5.2.3、精确到service包下的类以及该包下的子包的所有类

within(com.spring.service..*)

5.3、args(粒度是匹配参数的个数和参数的类型的方法)

5.3.1、精确匹配到只有一个String类型的参数的方法

args(java.lang.String)

5.3.2、精确匹配到参数开头是String类型,结尾是Integer类型,中间可以是任意个数和任意类型的参数。这里通配符用“…”,不能用“ * ”

args(java.lang.String,..,java.lang.Integer)

5.4、this和target的区别

5.4.1、用于环绕通知时,this和target里指定目标对象时,如果目标对象没有实现接口,则执行结果一样;如果目标对象实现了一个接口,this就不能执行环绕通知,但是target是可以的。

5.5、@within

5.5.1、粒度匹配到指定注解放在哪些类上,就对哪些类进行增强。

5.6、@annotation

5.6.1、与@within相似,@annotation是作用于方法上的。

5.7、@args

5.7.1、表示用注解标注的类作为参数时,被执行方法增强

5.8、@DeclareParents

5.8.1、表示为指定的目标类引入新的属性和方法。

5.9、perthis和pertarget

5.9.1、在多线程的情况下,进行创建Aspect类的多例

六、环绕通知

6.1、切面类如下:

步骤一: 添加注解@Around

步骤二:在通知方法上传入参数ProceedingJoinPoint,然后调用其方法proceed();


@Component
@Aspect
public class AspectTest {
    
    

    @Around("pointCut()")
    public void aroundTest(ProceedingJoinPoint proceedingJoinPoint) {
    
    
        try {
    
    
            System.out.println("环绕通知之前执行");
            proceedingJoinPoint.proceed();
            System.out.println("环绕通知之后执行");
        } catch (Throwable throwable) {
    
    
            System.out.println("异常通知执行。。");
        }
    }

    @Pointcut("execution(* com.xuecheng.aop.service..*.*(..))")
    public void pointCut() {
    
    

    }
}

七、可以获取目标方法的参数,并且可以对其修改

7.1、在通知方法内传入参数JoinPoint,并调用方法getArgs();获取目标方法的参数,并对其进行修改。

    @Around("execution(* com.xuecheng.aop.service..*.*(..))")
    public void aroundTest(JoinPoint JoinPoint) {
    
    
        //获取目标方法的参数,并可以对其进行修改
		// Object[] args = joinPoint.getArgs();
    }

八、通知(Advice)的分类

8.1、Spring切面定义了5种类型通知:

1)前置通知(Before):在目标方法被调用之前调用通知功能。

2)后置通知(After):在目标方法完成之后调用通知,不会关心方法的输出是什么。(不管目标方法是否成功执行,后置通知一定执行。)

3)返回通知(After-returning): 在目标方法成功执行之后调用通知。(在后置通知之前执行,必须方法执行成功后,才能执行!)

4)异常通知(After-throwing):在目标方法抛出异常后调用通知。

5)环绕通知(Around):通知包裹了被通知的方法,在被通知的方法调用之前和之后执行自定义的行为。(ProceedingJoinPoint参数可以有,但是JoinPoint不能存在。)

ProceedingJoinPoint 继承于 JoinPoint ;ProceedingJoinPoint里面有两个方法:proceed(); 和 proceed(Object object);

九、AOP术语

切点、连接点、切面、通知

连接点是切点的集合,连接点是一个飘渺的范围大的概念。切面是通知和切点的结合。通知告诉我们的是,“什么时候做?”和“做什么?”;而切点告诉我们的是,“在哪做?”

十、Aop的切面类的执行顺序

10.1、可以通过注解@order(1)解决执行的顺序,里面的数字越低,优先级越高。

十一、springAop改变目标方法的参数和对目标方法的返回值的返回后进行修改(仅适用于around(环绕通知))

也可以将改变后的参数传入目标方法的参数内执行

    @Around("pointCut()")
    public void before(ProceedingJoinPoint joinPoint)  {
    
    
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
    
    
            System.out.println("方法的参数是"+arg);
        }

        System.out.println("环绕之前。。。");
        try {
    
    
            String proceed = (String) joinPoint.proceed();
            proceed="改变后的返回值";
            System.out.println(proceed);
        } catch (Throwable throwable) {
    
    
            throwable.printStackTrace();
        }
        System.out.println("环绕之后。。。");


    }
测试代码
public class Demo {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AopConfig.class);
        TestService s = (TestService) applicationContext.getBean("s");
        s.ss("String参数。。");

    }
}
测试结果
方法的参数是String参数。。
环绕之前。。。
目标方法执行...String参数。。
改变后的返回值
环绕之后。。。

猜你喜欢

转载自blog.csdn.net/weixin_43983411/article/details/108125905