java小易——Spring

Spring

IoC DI AOP

spring底层用的是ConcurrentHashMap

解耦合:工厂模式:需要一个模板

控制反转 IoC

将原来有动作发起者(Main)控制创建对象的行为改成由中间的工厂来创建对象的行为的过程叫做IoC

一个类与工厂之间如果Ioc以后,这个时候,动作发起者(Main)已经不能明确的知道自己获得到的对象,是不是自己想要的对象了,因为这个对象的创建的权利与交给我这个对象的权利全部转移到了工厂上了

所用包:

DOM4j解析XML文件

lazy-init = "false"为懒加载,调用时进行加载,加载时创建对象

spring Core为核心包

spring bens为对象包

spring Context为上下文包

spring Context support

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    
    <!-- 加scope="prototype"则为多例,scope控制是否为一 -->
    
    <bean id ="service" class="com.yau.test.service.FooService" scope="prototype"></bean>
    
</beans>
IoC过程:把对象创建的过程反向交给Spring

Spring的IoC,其实我们管这个东西叫做容器。他是一个负责将将创建对象,以及保存对象的过程融合在自己的框架体系内的一个容器

所谓容器,就一定满足可以承载的内容的过程,而Spring承载的内容,是对象,其内部叫做Bean,这些个Bean是按照一个方式来保存的。

第一,容器:spring的容器是一个系列的继承链和依赖链,一般来说,用户在使用配置过程,直接使用的容器叫做:ApplicationContext(应用上下文)而这个容器的创建方式,是通过配置文件的加载过程来实现的,也就是说,SPring容器的启动与使用,是通过配置文件的加载来实现的。

如何加载配置文件等在DefaultResourceLoader

资源解析器必须有一个资源加载器DefaultResourceLoader

Spring IOC总结!

IoC为SPring的一个容器,Ioc加载过程其实依托与ApplicationContext,ApplicationContext为应用上下文,应用上下文通过一系列的继承,继承了AbstractApplicationContext抽象类,类里整合了两个资源,一个为ResourcePatternResolver解析文件里的内容与标签,另一个为ResourceLoader加载配置文件,创建ApplicationContext对象时,结合两个资源,通过Loader加载配置文件,Resolver加载配置文件内容,将配置文件中的bean创建出来,并放到BeanFactory中,拿对象时,调用的是AbstractApplicationContext里的getBean方法,看传进来的是Id,则为getBean(“id”),传的为类型则为getBean(类型).

第一:Spring启动必须启动容器,SPring的启动就是容器的初始化,启动,关键配置和对象进入容器的过程

第二:我们以Main里面通过ApplicationContext启动的过程为例。

​ a.启动首先需要加载配置文件,ApplicationContext加载的配置文件在ResourceLoader,这个类是需要将配置文件从文件系统读入到当前的Spring上下文的,这个ResourceLoader是ClassPathXMLAppliactionContext的父类,其直接子类是AbstractApplicationContext,而使用的ResourceLoader是Spring提供的DeaultResourceLoader.

​ b.在AbstractApplicationContext中(他自己是一个ResourceLoader),有一个ResourcePatternResolver这个资源类型解释器将你所设置的资源,按照类型解释成Spring所能加载的配置文件,Spring所能加载的配置文件包括(xml,jar,war,properties),资源类型解释器需要有一个资源加载器来辅助运行,这个资源加载器就是AbstractApplicationContext,因为它自己继承了DefaultResourceLoader.

​ c.BeanDefinition是Spring提供的对于Bean的定义类,其中的方法直接映射到配置文件中,我们对于一个Bean定义的时候所有可能用到的所有属性。

BeanFactory与FactoryBean区别

BeanFactory——>容器中包含了5个ConcurrentHashMap缓存,存对象的定义

FactoryBean——>用户自定义创建工具——>其他第三方与Spring直接的一个接口一样,使用来交由其他第三方创建并继承重写,然后由Spring创建时,发现是Factory,就调用其getBean方法,来获得真实的对象

<bean id="myfactory" class="com.yau.test.factory.MyFactory"></bean>
<!--创建哪个类,哪个方法的对象-->
<bean  name="service2" class="com.yau.test.service.TestService" factory-bean="myfactory" factory-method="yau"></bean>
依赖注入 DI

原理:反射

通过两个方式:①:get、set方法

​ ②:构造方法

创建对象时,使用的是IoC,IoC帮我们将对象创建好,好在BeanFactory容器里面,一切都是那么的美好,直到发生了一件事情,我们在创建一个对象的时候,需要给它的成员变量同时赋值,在创建一个对象的时候,有N个方法,在创建一个对象的时候,很多的参数需要指定,IoC能创建对象,但是IoC不能选择如何创建对象,也不能选择怎么给对象中的参数赋值。

​ IoC挣扎过,给出一个救命用的东西,FactoryBean,告诉客户,如果你想指定参数,你可以去重写FactoryBean来实现,但是客户都是懒人,不想这么麻烦,所以,Spring妥协,给出了更加优秀的解决方案,叫做DI(依赖注入)。

<!--DI 依赖注入-->
<bean id="myfactory" class="com.yau.test.factory.MyFactory">
    <property name=""  value=""></property>
</bean>

构造方法时:

<constructor-arg name="id" value="aaaa"></constructor-arg>

list赋多个值:

 <property name="list">
            <list>
                <value>yau</value>
                <value>fxw</value>
            </list>
        </property>

map赋值:

Spring创建的Map是什么Map?? 答:LinkedHashMap

   </property>
        <property name="map">
            <map>
                <entry>
                    <key><value>liguocheng</value></key>
                    <value>Java</value>
                </entry>
                <entry>
                    <key><value>hezhiyuan</value></key>
                    <value>Html</value>
                </entry>
            </map>
        </property>
自动装载autowire:

对于test,一般会有自动装配,存在自动装配时,byName为自动找名字为test的,装载进去

 <bean id ="foo" class="com.yau.test.bean.Foo" autowire="byName">
    </bean>

    <bean id="test" class="com.yau.test.bean.Test"></bean>

若为byType为自动找类型,找到与Foo中的类型相同的类型,将其装载进去

<bean id ="foo" class="com.yau.test.bean.Foo" autowire="byType">
</bean>

    <bean id="test" class="com.yau.test.bean.Test"></bean>
    <bean id="ts" class="com.yau.test.bean.Foo"></bean>
问题:循环依赖 A——>B——>A,Spring如何解决?

容器关联,父子容器

//父子容器的概念
//父容器,一个优先被创建出来的容器,其实就是一个Beanfactory(附带了5个ConcurrentHashMap)
ApplicationContext parent = new ClassPathXmlApplicationContext("application.xml");
//子容器出现了,子容器创建的时候,会将父容器继承的对象参数,再创建时,必须明确的指出。
//创建完成子容器后,我们发现,子容器中,出现了子容器的配置文件没有声明,但是父容器中已经声明过的对象
注解式开发:

配置文件中加入组件扫描,操作都在类中

**组件扫面component-scan:**扫描base-package里包的所有类和方法

<context:component-scan base-package="com.yau.test"></context:component-scan>

在某个类中加入@Component(" xxx"),组件的意思,直接扫描这个类,相当于配置文件中的,

<Bean id="xxx" class="被注解的这个类"></bean>

将内容加进来,直接扫描这个类,进行创建

在注解式中控制单例或多例,原型为@Scope(“prototype”),单例为@Scope(“singleton”),相当于配置文件中的

<Bean scope=" "></bean>

DI过程:虽然没有get、set方法,构造方法。但通过属性的访问,进行直接赋值

public class FooService implements IService{
    @Value("fxw帅")
    String count;//直接进行赋值
   public FooService(String count){
        this.count=count;
   }
   public FooService(){}
    @Override
    public void foo() {
        System.out.println("nihao:" + count);
    }

}
注解的总结

@Autowired 为将组件装载,是按照类型进行装载,万一有两个相同的,则不知道装载哪个,所以@Qualifier(“名字”)指定一个。

@Resource(name = “xx”)

如果为两个对象,则@Resource为按照名字加载,@Autowired与@Qualifier(“名字”)才是按照名字加载

@Configuration将当前类当作配置文件来用

@Pointcut切入点对象

@Aspect 提示类为配置增强的

@Controller将这个类交给Spring容器加载

@RequestMapping("/User")请求映射地址

@Repository为库,将类交给spring

面向切面编程 AOP

假说,当前,我们完成了一个功能的代码,这个功能的代码最终结果是往数据库中的添加一条数据。突然一天,你的老板过来了说,昨天晚上12点有一个人,通过你的这个功能,向数据库里面添加了一个数据,这个数据是骂老板的,你老板说,你要赶紧把这个人找出来。你怎么找??

​ 我们想到的第一个可能使用的方法,是修改添加到数据库中的数据格式。同时保存修改人信息,但是这个过程是比较好的么?

第二个可能使用的方法,是在执行这个已经完成的功能之前,记录一下日志,记录是谁,在几点,要干什么

再比如说,突然有一天,另一个人,通过你的代码里面的另一个功能,这个功能用来删除一条数据的,这个功能执行了,删除了一个非常重要的数据,你老板过来,需要你找到,是谁删除了这数据,你怎么找??

我们想到第一个可能使用的方法,是修改删除的逻辑,并不是真的删除这个数据,而是以后不显示这个数据了,第二个可能使用的方法,是删除之前记录一下谁要去删除,删除什么

你成功挺过去前两次,又有一天,你写了一个功能,然后测试已经通过了,都没有问题了。突然产品经理,携老板出现在你的面前说,客户那边要的功能变化,需要小改动,在你执行这个功能之前,需要先验证,传递参数正确不正确

想到第一个可能使用的方法,是修改原来的执行逻辑,添加进来对于传输的内容的判断,第二个可能使用的方法,写一个新的,在已经完成的功能之前执行的方法,使用代理模式,让那个验证方式先执行。

AOP:面向切面编程,就当你已经完成,或者更加注意一些核心功能的时候,需要使用的编程过程,这个使用,你会发现,一个核心的业务,是由一个核心功能,和若干个额外服务类型的功能,统一组成的,比如刚才的数据验证,再比如日志的记录。

其实再场景中,我们的核心功能是针对数据库的操作,可能是增删过程,而服务器功能,比如记录日志,或者输入内容的验证过程,其实不是非有不可,没有这个功能,核心功能也能正常执行。

这个时候,我要考虑一个问题,这些必要或者非必要的额外功能,是不是要写在你的核心代码过程当中啊??

我们现在,将核心业务,做一个简单的切分,核心功能与辅助功能

明确一些名词:

切点:Pointcut 在某些个核心方法之前,之后等位置

切面:很多个切点组成的过程叫做切面

增强:理解成辅助功能

织入:将辅助功能安装在切点上的过程

配置:

<aop:config></aop:config>

织入:

<aop:aspect></aop:aspect>
切点:

*切点表达式:execution(返回值 全包名.类名.方法名(参数集合) ) 通配符

一个点:com.yau.test.service. 这个下面的包

二个点:com.yau.test.service. . 这个下面的包以及子包

<aop:pointcut id="methodsBefore" expression="execution(* com.yau.test.service.*.*(..))"/>
增强:Advice(也叫通知) 主要是用来告诉AOP,我们在切点(目标方法上),应该在什么时机执行什么功能

①:若上面定义了,则下面可以写pointcut-ref=“methodsBefore”

<aop:pointcut id="methodsBefore" expression="execution(* com.yau.test.service.*.*(..))"></aop:pointcut>
<aop:advisor advice-ref="myBeforAdvice" pointcut-ref="methodsBefore"></aop:advisor>

②:若没有上面的定义

<aop:advisor advice-ref="myBeforAdvice" pointcut="execution(* com.yau.test.service.*.*(..))"></aop:advisor>
增强时机得选择有以下几种:来源是AspectJ(面向切面框架)

前置增强:before

后置增强:after

环绕增强:around,可以改变参数,而且可以拒绝方法的执行

异常增强:throw

返回增强:after returning

<aop:config>
        <aop:pointcut id="methodsBefore" expression="execution(* com.yau.test.service.*.*(..))"></aop:pointcut>
        <aop:aspect ref="myAdvisor">
            <aop:before method="before" pointcut-ref="methodsBefore"></aop:before>
            <aop:after method="after" pointcut-ref="methodsBefore"></aop:after>
            <aop:after-returning method="afterReturning" pointcut-ref="methodsBefore"></aop:after-returning>
            <aop:after-throwing method="afterThrowing" pointcut-ref="methodsBefore"></aop:after-throwing>
        </aop:aspect>
</aop:config>
增强关系:

before、after必执行,不管是什么异常,碰见异常,没有捕获但抛出了,走afterThrowing,正常执行时,没异常,则走afterReturning,不管如何,加入环绕增强,必须由环绕增强处理

实现增强的三种方式:

一、继承Spring给出的对应增强接口

二、aop配置时,通过aop:aspect配置增强类型,在方法中可传入两种参数,除around以外传入的参数为joinPoint,around传入参数为ProceedingJoinPoint

三、通过注解来实现,配置文件中加入以下

①:扫面所有的注解包,将增强类作为容器对象创建出来

<context:component-scan base-package="com.yau.test"></context:component-scan>

②:开启注aop注解驱动,aspectj的自动代理

<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

③:在增强类上加两个注解:①@Aspect 提示类为配置增强的,②@Configuration提示为配置文件,两种方式,可以直接在@before中写execution()切点表达式,也可以通过@Pointcut来写,如下:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHRNJenn-1594374137972)(F:\A——java学习库\java笔记图片库\Spring\Aop.png)]

aspectJ带入的一个参数JoinPoint,为黏结点,结合点,提供一些方法,joinPoint.getArgs().length为参数的长度等

其他几种方法参数为(JoinPoint joinPoint)但是在around方法中传入的参数为around(ProceedingJoinPoint pjp)
public void before(JoinPoint joinPoint){
    System.out.println("before")
}

public void afterReturning(JoinPoint joinPoint){
    System.out.println("afterReturning")
}

 @Around("point")
    public Object around(ProceedingJoinPoint pjp){
        System.out.println("around");
    }
动态代理:没有代理模式,根据这个类动态生成一个代理模式

两种生成代理的方式,一种JDK原生动态代理(Java Proxy),一种spring的CGlib动态代理

区别:JDK生成快,CGlib执行快,JDK生成的时候,只能根据接口去生成,之后InvocationHandler执行内部方法,所以速度快, CGLIB全部切开,生成的就慢,但是分的很细,执行就快
开启CGLIB代理模式:
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
开启后,不管是类与接口都是用继承,CGLIB生成,如果为false,接口的话默认用JDK原生动态代理,如果类型的话默认为CGLIB。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值