计算机系统应用教程网站

网站首页 > 技术文章 正文

每日一练进击大厂「DAY9」Spring1

btikc 2024-10-15 09:04:26 技术文章 10 ℃ 0 评论

文章目录

  • 一、什么是Spring
  • 二、Spring的模块有哪些
  • 三、简单说一下对Spring的理解
  • 四、Spring的控制反转(IOC)
  • 五、SpringIOC的工作流程
  • 六、Spring的依赖注入(DI)
  • 七、Spring中AOP的底层是怎么实现的
  • 八、AOP相关注解
  • 九、Bean是如何创建的
  • 十、Bean的作用范围
  • 总结

一、什么是Spring

Spring是JAVA企业级应用的开源开发框架,Spring主要用来开发JAVA应用,但是有些扩展是针对构建J2EE平台的web应用,Spring框架目标是简化JAVA企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。

二、Spring的模块有哪些

  • Spring Core:基础,spring其他所有的功能都依赖于该类库
  • Spring AOP:提供面向切面的编程实现
  • Spring JDBC:数据库连接
  • Spring JMS:java消息服务
  • Spring ORM:用于支持Hibernate等ORM工具
  • Spring Web:为创建web应用程序提供支持
  • Spring Test:提供了为Junit和TestNG测试的支持
  • Spring Tx:事务

三、简单说一下对Spring的理解

  • Spring是一个开源框架,是一个IOC和AOP容器框架。
  • Spring帮助我们管理对象及其依赖关系。
  • 是基于POJO的轻量级和最小侵入性编程。
  • 通过依赖注入进行控制反转。
  • 通过依赖注入和面向接口来松耦合。

四、Spring的控制反转(IOC)

IOC:Spring容器使用了工厂模式为我们创建了所需要的对象,我们使用时不需要自己去创建对象,直接调用Spring为我们提供的对象即可,这就是控制反转的思想。原来控制权在用户,现在的控制权完全交给了容器,在bean实例化后,通过反射对属性进行依赖注入。

实现IOC的两种方式:XML方式、注解的方式。

XML加载的方式,首先在Spring的xml中通过bean标签配置我们需要注入的bean。当扫描到所有的bean后, 将bean包装成BeanDefinition,放入list中,然后循环这个list去创建bean。
创建Bean的步骤为:

  1. 实例化
  2. 属性注入
  3. 初始化
  4. AOP
    最终放入到Spring的一级缓存中保存起来。

注解的方式是通过在类上面添加Spring相关的注解,比如@Controller、@Service等,spring会扫描这些注解来作为Beaning封装成BeanDefinition。后续和xml的处理方式是相同的。

五、SpringIOC的工作流程

第一个阶段,IOC容器的初始化。
这个阶段主要是根据程序定义的XML或者注解等Bean的声明方式,通过解析和加载后生成BeanDefinition,然后把BeanDefinition注册到IOC容器,通过注解或者XML声明的bean都会解析得到一个BeanDefinition实体,实体中包含这个bean中定义基本属性,最后把这个BeanDefinition保存到一个Map集合中,从而完成了IOC的初始化。
第二个阶段,完成Bean初始化及依赖注入。
通过反射对没有设置lazy-init属性的单例bean进行初始化,完成bean的依赖注入。
第三个阶段,Bean的使用
通常会通过@Autowired或者BeanFactory.getBean()从IOC容器中获取指定的bean实例。针对设置lazy-init属性以及非单例bean的实例化,是每次获取bean对象的时候,调用bean的初始化方法来完成实例化的,并且SpringIOC容器不会去管理这些bean。

六、Spring的依赖注入(DI)

DI:Spring使用java bean对象的set方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程就是依赖注入的思想。

七、Spring中AOP的底层是怎么实现的

Spring中AOP底层的实现其实是基于JDK的动态代理和cglib动态创建类进行动态代理来实现的;
如果要代理的对象,实现了某个接口,那么SpringAOP会使用JDK Proxy,去创建对象。如果没有实现接口的对象,就无法使用JDK Proxy去进行代理了,这时候SpringAOP会使用Cglib生成一个被代理对象的子类来作为代理。

基于JDK的动态代理的原理是:
需要用到的几个关键成员,InvocationHandler(想要通过动态代理生成的对象都必须实现这个接口),真实需要代理的对象(帮你代理的对象),Proxy对象(是JDK中java.lang.reflect包下的)。
首先真实要代理的对象必须要实现InvocationHandler这个接口,并且覆盖这个接口的invoke方法,这个Invoke中方法的参数的proxyObject就是你要代理的真实目标对象,方法调用会被转发到该类的invoke方法,method是真实对象中调用方法的Method类,Object args是在真实对象中调用方法的参数;
然后通过Proxy类去调用newProxyInstance(classLocader ,interfaces,handler)方法,classLoader是指真实代理对象的类加载器,interfaces是指真实代理对象需要实现的接口,还可以同时指定多个接口,handler方法调用的实际处理者(帮你代理的那个对象),代理对象的方法调用都会转发到这里,然后直接就能生成你想要的对象类了。

JDK代理代码举例实现

public class Application {

    public static void main(String[] args) {

        RpcProxyClient client = new RpcProxyClient();
        IHelloService service = client.clientProxy(IHelloService.class,"localhost",8888);
        String xinyu = service.sayHello("xinyu");
        System.out.println(xinyu);


    }
}

public class RpcProxyClient {


    public <T>T clientProxy(final Class<T> interfaceCls,final String host,final int port){
        return (T) Proxy.newProxyInstance(interfaceCls.getClassLoader(),
                new Class<?>[]{interfaceCls},new RemoteInovcationHandler(host,port));
    }

}

public class RemoteInovcationHandler implements InvocationHandler {

    private String host;
    private int port;

    public RemoteInovcationHandler(String host, int port) {
        this.host = host;
        this.port = port;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("触发了调用的代码");

        RpcRequest request = new RpcRequest();
        request.setClassName(method.getDeclaringClass().getName());
        request.setMethodName(method.getName());
        request.setParameters(args);
        request.setTypes(method.getParameterTypes());
        //TODO 编写业务逻辑代码

        return resut;
    }
}

八、AOP相关注解

  • @Aspect:声明被注解的类是一个切面bean。
  • @Before:前置通知,指在某个连接点之前执行的通知。
  • @After:后置通知,指在某个连接点退出时执行的通知。
  • @AfterReturning:返回后通知,指某个连接点正常完成之后执行的通知,返回值使用returning属性连接。
  • @AfterThrowing:异常通知,指方法抛出异常导致退出时执行的通知,和@AfterReturning只会有一个执行,异常使用throwing属性接收
@Component
@Aspect
@Slf4j
public class AnnotaionAspectDemo {

    @Pointcut("execution(* com.xinyu.view.interviewproject.spring..*(..))")
    public void aspect() {

    }

    @Before("aspect()")
    public void before(JoinPoint joinPoint) {
        log.info("before通知" + joinPoint);
    }

    @After("aspect()")
    public void after(JoinPoint joinPoint) {
        log.info("after通知" + joinPoint);
    }

    @Around("aspect()")
    public void around(JoinPoint joinPoint) {
        long l = System.currentTimeMillis();
        try {
            ((ProceedingJoinPoint) joinPoint).proceed();
            long l1 = System.currentTimeMillis();
            log.info("around通知" + joinPoint + "time" + (l1 - l));

        } catch (Throwable throwable) {
            long l1 = System.currentTimeMillis();
            log.info("around通知" + joinPoint + "time" + (l1 - l));
        }
    }

    @AfterReturning("aspect()")
    public void afterReturn(JoinPoint joinPoint) {
        log.info("afterReturn通知" + joinPoint);
    }

    @AfterThrowing(pointcut = "aspect()", throwing = "ex")
    public void afterThrow(JoinPoint joinPoint, Exception ex) {
        log.info("afterThrow通知" + joinPoint + ex.getMessage());
    }

}

九、Bean是如何创建的

第一步:找到哪些Bean需要去实例化,xml方式、注解的方式去找,封装成一个BeanDefiniton放入到list中;
第二步:循环list创建一个个bean对象

  1. 实例化
  2. 属性注入
  3. 初始化
  4. aop

第三步:放入到一级缓存中

十、Bean的作用范围

  • singleton:单例模式,是默认作用域,不管收到多少Bean请求每个容器中只有一个唯一的Bean实例。
  • prototype:原型模式,和singleton相反,每次Bean请求都会创建一个新的实例。
  • request:每次HTTP请求都会创建一个新的Bean并把它放到request域中,在请求完成后Bean会失效并被垃圾收集器回收。
  • session:和request类似,确保每个session中有一个Bean实例,session过期后bean会随之失效。
  • global session:当应用部署在Portlet容器时,如果想让所有Portlet共用全局存储变量,那么该变量需要存储在global session中。

总结

人生的意义就是活着,而活着却是遭罪。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表