Spring
2021-10-14 14:36:57 18 举报
AI智能生成
spring
作者其他创作
大纲/内容
面向切面编程思想:简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。作用:在程序运行期间,不修改源码对已有方法进行增强。优势:减少重复代码提高开发效率维护方便
底层为动态代理:对目标类进行功能增强
Joinpoint(连接点)
所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。理解:就是需要增强的方法 不是所有方法都需要增强
Pointcut(切入点)
Advice(通知/增强)
Introduction(引介)
代理的目标对象
Target(目标对象)
是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
Weaving(织入)
一个类被AOP织入增强后,就产生一个结果代理类
Proxy(代理)
是切入点和通知(引介)的结合
Aspect(切面)
AOP相关术语
缺点:需要直到要增强的方法的类才能继承
继承
装饰者模式就是静态代理的一种体现。
缺点:静态代理是字节码一上来就创建好,并完成加载,代码是写死的。需要有接口,这个接口下除了要增强的方法外别的方法也要实现
装饰者模式
字节码随用随创建,随用随加载
特点
要求:需要接口但可以指定增强方法,不需要实现全部方法
参数含义:ClassLoader:和被代理对象使用相同的类加载器。Interfaces:和被代理对象具有相同的行为。实现相同的接口。InvocationHandler:该接口的实现类(一般写匿名内部类)如何代理(如何增强)。 策略模式:使用场景是: 数据有了,目的明确。 如何达成目标,就是策略。
创建代理对象
执行被代理对象的任何方法,都会经过该方法。此方法有拦截的功能。
参数:proxy:代理对象的引用。不一定每次都用得到method:当前执行的方法对象args:执行方法所需的参数返回值:当前执行方法的返回值谁调用返回给谁 返回的内容就是最终值而不是需要增强的方法的返回值
重写的invoke方法
如何代理
代码示例
步骤
内部类中使用但未声明的任何局部变量必须在内部类的正文之前明确分配。Java匿名内部类的方法中用到的局部变量都必须定义为final,原因:java中规定,内部类只能访问外部类中的成员变量,不能访问方法中定义的变量,变量声明为final(常量)的,使变量全局化,就相当于是在外部定义的而不是在方法里定义的
通过if-else判断方法名来增强指定方法
细节
基于接口的动态代理:JDK官方的Proxy类提供
要求:被代理对象不能是最终类
不需要接口,可以指定增强方法,但代码量比较大
该代理模式是用拦截器和过滤器的方式进行继承,对目标类的方法进行增强
CGLIB原理
方法的参数:Class:被代理对象的字节码 Callback:如何代理
参数:前三个和基于接口的动态代理是一样的。MethodProxy:当前执行方法的代理对象。
如何代理,重写intercept方法,类似上面
基于子类的动态代理:第三方的CGLib提供
动态代理模式
对目标类方法进行加强的方式
确定目标类(要被切的类,即需要被加强的类),需要定义切入点,此处切入点为需要增强的方法
确定切面类,即用来切类的刀,需要定义增强后的方法
织入配置,把增强方法指定在切入点前置、后置、环绕、异常、最终 执行
表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
全通配方式: * *..*.*(..)
通常情况下,我们都是对业务层的方法进行增强,所以切入点表达式都是切到业务层实现类。execution(* com.google.service.impl.*.*(..))
切入点表达式写法
配置文件
<aop:config> <aop:aspect id=\"logAdvice\" ref=\"logger\"> <!--配置环绕通知 详细注释在Logger实体类中--> <aop:around method=\"aroundPrintLog\" pointcut-ref=\"accountCut\"></aop:around> </aop:aspect> </aop:config>
它是spring框架为我们提供的一种可以在代码中手动控制增强代码什么时候执行的方式通常情况下,环绕通知都是独立使用的
Object[ ] args=pjp.getArgs;//参数为切入点的参数Obeject rtvalur=proceed(args)//返回值为切入点的返回值
Logger类中环绕通知方法代码
环绕通知配置
用<aop:before>标签配置
前置增强
用<aop:after-returning>标签配置
在原方法执行结束后介入增强后的方法
后置增强
用<aop:around>标签配置,需要在增强后的方法中传参:ProceedingJoinPoint类型的对象,这个对象中包含着目标类需要增强的方法,需要在增强后的方法中调用pjp.proceed()方法,相当于调用原方法,在该方法前后需要写自己的业务逻辑实现环绕介入
环绕增强
用<aop:after-throwing>标签配置
在原方法发生异常时会介入,一般用于对数据库事务的处理
异常增强
用<aop:after>标签配置
在需要增强的方法正确地返回之后执行
最终增强
织入时机
基于XML配置
<!--config作用:用于声明开始aop的配置--> <aop:config> <!-- aspect配置切面 即代理类 里面包含将目标类增强后的方法 --> <aop:aspect id=\"logAdvice\" ref=\"logger\
定义切面类,让其实现特定接口(五类织入时机)
确定目标类(被介入的类),确定其切点
确定切面类(做介入角色的类)
<aop:config> <!-- 定义切点 即需要被增强的方法 --> <aop:pointcut id=\"empCut\" expression=\"execution(..........)\"></aop:pointcut> <!-- 定义切面 指向bean标签中的切面类 包含切点(指向上方的切点) --> <aop:advisor advice-ref=\"bean标签对应的切面类\" pointcut-ref=\"empCut\"></aop:advisor></aop:config>
定义的切面类需要实现MethodBeforeAdvice接口并实现befor方法
该方式底层会调用目标类中需要增强的方法,在该切面类中的before方法中只需要写自己的业务逻辑即可
定义的切面类需要实现AfterReturnAdvice接口并实现afterReturn方法
原方法返回值
Object returnValue
目标方法
Method method
目标方法执行需要的参数数组
Object[] args
目标对象,即被代理的类的对象
Object target
参数
切面类需要实现MethodInterceptor接口并实现invoke(MethodInvocation invocation)方法
切面类实现ThrowsAdvice接口,该接口是一个空接口,需要在该切面类中自定义名为afterThrowing(Exception e)方法
基于实现接口方式的aop
基于接口规范式
基于注解整合时,导入约束时需要多导入一个context名称空间下的约束。
<!--配置spring创建容器时要扫描的包--> <context:component-scan base-package=\"com.google\"></context:component-scan> <!--配置spring开启注解AOP的支持--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
xml开启注解
基本不用配置文件
用IOC实例化对象
@Component(\"txManager\") @Aspect//表明当前类是一个切面类 public class TransactionManager {...}
@Aspect
@Pointcut(\"execution(* com.google.service.impl.*.*(..))\") private void accountCut(){}
@Pointcut
@Before
@AfterReturning
@AfterThrowing
@After
@Around单独使用
注解
纯注解:@Configuration @ComponentScan(basePackages=\"com.google\") @EnableAspectJAutoProxy //多了一行 spring开启注解AOP的支持public class SpringConfiguration { }
写一个类,用新注解标注,可以让该类的作用和application.xml的作用一样
细节:表名该被标注的类是一个配置类,但本质作用并不是标注它是一个配置类,而是加上这个注解之后,该类中的所有方法会被CGLib代理,方法会跟原来的方法完全不一样,这样就保证了对象的生命周期和作用域。如果不加该注解,在该类中用Bean注解照样好用,用AnnotationApplicationContext去容器取对象也好用,只不过如果该类中的一个创建对象的方法调用了另一个创建对象的方法,那么另一个对象将被创建多次,不能保证对象的单例,即作用域scope不能被保证
@Configuration
通过该注解告诉spring在创建容器时需要扫描的包
属性value,和xml配置文件中的<context:component-scan>标签中的basePackage属性作用一样
@ComponentScan
用于标注配置类中的方法,将方法的返回值对象存入spring容器中
name属性用于定义bean的id,当不写时,存入容器集合时key默认为方法名,值为对象
@Bean
依然可以使用@Scope:定义类的单例多例
用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置
属性: value[]:用于指定properties文件位置。如果是在类路径下,需要写上classpath:
@PropertySource
用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解。
@Import
细节:当我们使用注解配置方法时,如果方法有参数,spring会自动去容器中找有没有可用的bean,查找的方式与@Autowired注解的方式一致
我们已经把要配置的都配置好了,但是新的问题产生了,由于没有配置文件了,如何获取容器呢?此时不再使用ClassPathXmlApplicationContext,而是要用AnnotationConfigApplication,并将该配置类的class对象传入
spring新注解(配置我们无法修改的类和配置扫描注解的类路径)与IOC一样
基于注解配置
AOP的三种方式
AOP
Spring的事务控制都是基于AOP的,它既可以使用编程的方式实现,也可以使用配置的方式实现。学习的重点是使用配置的方式实现
我们使用DataSourceTransactionManager这一实现类 主要针对dbutils和jdbcTemplate 对jdbc的封装这个实现类就是一个切面类
PlatformTransactionManager 平台事务管理器 是一个接口 定义了开启事务、提交事务、回滚的方法
TransactionDefinition:定义事务参数的接口
TransactionStatus:事务运行状态接口
Spring中事务控制的API/硬编码
事务包spring-tx.jar
AOP联盟
aspectj.jar
spring-aspects.jar
事务依赖包
导入依赖坐标
<bean id=\"事务管理器名\" class=\"事务类全路径\"> <property name=\"\" ref=\"bean标签中的数据源\"></bean>
例<bean id=\"transactionManager\" class=\"org.springframework.jdbc.datasource.DataSourceTransactionManager\"> <property name=\"dataSource\" ref=\"dataSource\"></property></bean>
第一步:配置事务管理器并注入数据源
即声明事务
<!-- 事务的配置 --> 事务名 需要的事务管理器名<tx:advice id=\"txAdvice\" transaction-manager=\"transactionManager\"> <tx:attributes> <!-- 需要进行事务管理的方法 --> <tx:method name=\"*\" read-only=\"false\" propagation=\"REQUIRED\"></tx:method> <tx:method name=\"find*\" read-only=\"true\" propagation=\"SUPPORTS\"></tx:method> </tx:attributes></tx:advice>
第二步:配置事务的通知引用事务管理器
<!--在 tx:advice 标签内部 配置事务的属性 --><tx:attributes><!-- 指定方法名称:是业务核心方法 read-only:是否是只读事务。默认 false,不只读。 isolation:指定事务的隔离级别。默认值是使用数据库的默认隔离级别。 propagation:指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。 查询方法可以选择SUPPORTS。 timeout:指定超时时间。默认值为:-1。永不超时。 rollback-for:用于指定一个异常,当执行产生该异常时,事务回滚。产生其他异常,事务不回滚。 没有默认值,任何异常都回滚。 no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时,事务回 滚。没有默认值,任何异常都回滚。
第三步:配置事务的属性
<aop:config> <aop:pointcut id=\"accountCut\" expression=\"execution(* com.google.service.impl.*.*(..))\"/> <aop:advisor advice-ref=\"txAdvice\" pointcut-ref=\"accountCut\"></aop:advisor></aop:config>
第四步:配置AOP切入点表达式
<!-- 在aop:config标签内部:建立事务的通知和切入点表达式的关系 --> <aop:advisor advice-ref=\"txAdvice\" pointcut-ref=\"accountCut\"/>
第五步:配置切入点表达式和事务通知的对应关系
声明式/基于XML配置
导入依赖jar包
约束DataAccess ctrl+f
半注解:创建spring的配置文件导入约束并配置扫描的包
xml配置事务管理器并注入数据源
可以在具体方法定义,优先级更高
在业务层使用@Transactional注解
<!-- 开启 spring 对注解事务的支持 --><tx:annotation-driven transaction-manager=\"transactionManager\"/>
在配置文件中开启spring对注解事务的支持
注意:使用注解时不能继承JdbcDaoSupport了需要自己定义private JdbcTemplate template,因为jar包中我们无法使用注解
类似多了个@EnableTransactionManagement
与其他一样
纯注解
基于编程式(了解)还没看
Spring事务管理
springmvc实际上是springframwork的一个模块,这个模块主要是对web的支持
springmvc是基于IoC和aop的
什么是springmvc
获取参数比较繁琐,如果类型不是字符串类型则需要进行类型转换,还需要判断是否为空
如果每个servlet对应一个请求,则会产生大量的servlet,如果一个servlet对应多个请求,则违反可单一原则
servlet缺点
springmvc提供了一个servlet,我们把所有的请求都发送给这个servlet,这个servlet我们称之为核心控制器
核心控制器在tomcat启动时就会创建,在其init方法中会读取配置文件并扫描指定的包,会为由@Controller注解标记的类创建对象,并把所有的由@RequestMapping注解标记的映射关系放到HandlerMapping中,键放注解的地址,值放方法
当在地址栏输入地址,核心控制器会根据资源路径从HandlerMapping中寻找要执行的方法,找到后并调用
在控制类的方法中处理请求和响应,用return实现请求转发(携带的参数放到ModelMap中)和重定向(在返回的字符串前加redirect)
原理
作用:帮我们找到对应的controller
依赖BeanNameUrlHandlerMapping类
传统开发方式,即配置文件方式
AnnotationMethodHandlerAdapter(过时的注解开发方式)
注解开发方式,已过时类
RequestMappingHandlerAdapter(最新版本的注解开发方式)
注解开发方式,最新类
在springmvc内部配置文件中,注解开发方式配置的还是过时的注解驱动类,需要在springmvc配置文件中用<mvc:annotation-driven/>标签配置新版注解驱动类
HandlerMapping
处理器映射器
作用:帮我们找到响应的方法
方法返回ModelAndView
处理器适配器
将结果渲染成页面
视图解析器
三大核心组件
标记控制类,该类拥有处理请求的能力
@Controller
标注方法,定义请求路径
窄化映射,可以定义到controller类上,隔离各个控制类中的方法
标注这个方法处理请求的地址,支持传数组,可以响应多个请求
value和path属性
设置接收的请求的请求方式
method
@RequesMapping
@ResponseBody
设置跨域访问
传统方式需要设置响应头setHeader(\"Access-Control-Allow-Origin\
同源指的是同一个服务器
如果a服务器向b服务器发送ajax请求,b服务器接收并响应数据,在默认情况下,a服务器的ajax拒绝接收b服务器的响应,所以需要在b服务器端设置跨域访问,解决跨域错误问题
浏览器的同源策略
@CrossOrigin
用于绑定url的占位符,例如:在请求的url中,/emplist/{empId},{empId}就是一个占位符,在参数列表中想要对应占位符的参数前用该注解标注,该注解中的值应当与占位符的值一致。url支持占位符是在spring3.0以后引入的
用于实现restful风格
如果想要实现restful风格,则需要将web.xml文件中核心控制器的请求路径设置为/,但此时将会把所有的静态文件例如js、css等也作为请求发送到核心控制器并去找相应的方法执行,此时就会访问不到静态资源,所以释放静态资源
在springmvc配置文件中配置静态资源,用<mvc:resources location=\"请求地址例如:/js/(以js开头的请求)\" mapping=\"映射位置例如 :/js/**(项目下js文件夹下所有的文件的子文件)\" />
用占位符的方式接收参数,占位符的参数名叫啥,前端name应该叫啥
RequestMapping(\"/delete\")localhost:8080/delete?id=10
传统风格
RequestMapping(\"/delete/{id}\")restful风格:localhost:8080/delete/10
restful风格
@PathVaribale
被该注解标注的方法会先执行
适用场景:当前端提交表单,带着表单数据向控制类中的某个方法发送请求,但表单数据并不是一个完整的JavaBean对象的数据,此时可以定义一个新的方法,用该注解标注,那么在执行对应请求方法时会先执行该方法,该方法也可以从请求中获取请求参数,可以在该方法中通过请求参数从数据库查询完整数据,并将最后JavaBean对象返回,这样数据就会完整,另一种方式是无返回值方法,可以参参数列表定义一个map集合,将最后的JavaBean放入map集合中,在对应的请求方法的参数列表中也用ModelAttribute注解标注参数,并在注解中给出放入map集合的key
@ModelAttribute
在spring4.2.x版本及以后出现了复合注解
@GetMapping(\"/\")
直接指明请求方式
@PostMapping
@Controller和@ResponseBody的符合注解
@RestController
注解语法糖
控制类中的注解
request
response
session
ModelMap
默认参数绑定
在对应方法的参数列表中定义请求参数
类型写你需要的,底层会帮你转,要求参数列表中的参数名与请求参数名一致
mvc会反射你的方法参数列表,根据参数名去找请求参数对应的值,会尝试将数据转成你想要的类型,如果不能转成你想要的,抛异常
基本数据类型
可以使用对象接收,在参数列表定义对象类型,mvc可以直接自动封装成对象,前提是对象的属性名跟请求参数名一致
bean方式
绑定包装的bean
一般用于批量删除,在前端定义复选框,复选框的名称相同且和控制类对应方法的数组名一致,springmvc可自动帮你获取参数
数组绑定
应用场景不多,一般用于批量修改,前端修改n条数据,提交多个对象到后台,但只能支持向对象中接收集合,即控制类对应方法中需要定义一个集合,接收参数时会接收到该对象的集合中,而且要求前端name属性为集合名[下标].对象属性名在jsp页面的c:foreach标签中的status属性可以获取遍历的集合的每次索引值
集合绑定
@RequestParam注解,标记参数列表
指明要获取的参数名,用于跟请求参数名匹配
value/name
默认为true,要求请求参数必须有,如果没有,则出现400,设为false则可以没有
required
用于定义参数列表的默认值,如果请求参数没有传来,则默认值生效
defaultValue
注解属性
注解方式
当前端参数出现springmvc无法自动转换的参数时,例如时间,可以使用自定义转换器
实现convert(T t)方法并返回想要的
在注册新版处理器映射器,处理器适配器驱动时,将自定义转换器配置<mvc:annotation-driven conversion-service=\"自定义转换器id\"/>
配置自定义转换器<bean id=\"\" class=\"org.springframework.format.support.FormattingConversionServiceFactoryBean\"> <property name=\"convers\"> <set><bean class=\"自己定义的转换器类的全限定名\"/></set> </property></bean>
将自定义转换器配置到springmvc容器中
将spring不支持的绑定类型参数上用@DateTimeFormat(pattern = \"yyyy-MM-dd HH:mm:ss\")
注解方式解决mvc不支持的参数绑定
自定义转换器
参数绑定
在方法中直接return页面地址默认就是请求转发
在返回的页面地址字符串前加redirect:则为重定向
例如
请求转发携带的参数需要放到ModelMap中
@RequestMapping(\"/listEmp\")public String ListEmp(ModelMap modelMap) { List list = empMapper.listEmpDept(); modelMap.put(\"empList\
返回String类型的地址
在spring配置文件中配置前缀和后缀
配置语法
将配置文件的前缀和后缀与控制类中方法return的字符串拼接即可得到想要的路径
配置视图解析器
<bean class=\"org.springframework.web.servlet.view.InternalResourceViewResolver\"> <!-- 配置前缀 --> <property name=\"prefix\" value=\"/WEB-INF/pages/\"/> <!-- 配置后缀 --> <property name=\"suffix\" value=\".jsp\"/></bean>
springmvc如何响应
框架提供的有跟过滤器功能类似但更强大的拦截器
在controller类中方法执行前被拦截
在controller类的方法执行之后但在视图解析前被拦截
方法执行完且视图解析之后拦截
拦截器会拦截Controller类中方法的调用
1. 定义一个类实现HandlerInterceptor接口
该接口中的方法为默认方法,每个方法都有不同的拦截时机
在controller的方法被调用之前执行该方法
在方法被调用视图解析之前调用
在方法执行完视图解析之后调用
2. 实现该接口中的方法,所有的方法返回值为boolean,真放行,假拦截
<mvc:interceptors> <mvc:interceptor> <!-- 配置哪个方法需要拦截 --> <mvc:mapping path=\"/**\"> <!-- 配置哪个方法不需要拦截 --> <mvc:exclued-mapping path=\"\"> <!-- 设置拦截器类路径 --> <bean class=\"拦截器类全限定名\"> </mvc:interceptor></mvc:interceptors>
3. 在配置文件中配置拦截器,可以配置多个拦截器,哪个在上边,最先执行哪个拦截器
快速入门
两个兰拦截器,1拦截器配置在前,2拦截器配置在后
执行顺序
拦截器
浏览器通过input标签将需要上传的文件自动读入到内存,当提交表单的时候,会将该文件发送到后台核心控制器,在请求中会携带这个文件,此时会调用到文件解析器,文件解析器会解析请求对象,将请求对象的文件解析出来返回给核心控制器
核心控制器再调用处理器映射器,找到相应的控制类的方法,通过参数绑定的形式,绑定给该方法,该方法的参数类型必须是MultipartFile类型,参数名必须要和input标签中的name属性保持一致,最后调用该MultipartFile对象的方法进行上传
springmvc文件上传原理
文件解析器配置
1. 表单提交方式一定是post
2. 表单的enctype的值一定是multipart/form-data
3. input的type一定是file
传统表单方式
1. type:post
2. data:FormData
3. processData: false
ajax方式
页面要求
1. 需要两个jar包commons-io.jar和commons-fileupload.jar
2. 在ppringmvc配置文件中配置文件解析器
3. 绑定参数类型一定为MultipartFile,参数名字要和input的name属性的值保持一致
springmvc要求
前后端要求
文件上传
都基于mvc设计模式
底层都是对ServletAPI的封装
处理请求的机制都是一个核心控制器
相同点
springmvc的入口是Servlet,struts2的入口是Filter
springmvc的最小单元是方法,是基于方法设计的,struts2的最小单元是基于类,每次执行都会创建一个动作类,所以mvc更快
springmvc使用更简洁,发送ajax更方便
s2的OGNL表达式使页面开发效率更高,但执行效率没有并没有比JSTL有所提升
区别
springmvc和struts2优劣
Springmvc
Spring框架对JDBC的简单封装。提供了一个JDBCTemplate对象简化JDBC的开发
1、导入依赖坐标
JdbcTemplate依赖于DataSource
c3p0
DBCP
Druid
Spring 内置数据源
配置数据源
配置JdbcTemplate注入数据源
2、配置xml或者使用properties
3、使用IOC创建对象
update():执行DML语句。增、删、改语句
将列名作为key,将值作为value 将这条记录封装为一个map集合 * 注意:这个方法查询的结果集长度只能是1
String sql = \"select * from emp where id = ? or id = ?\
queryForMap():查询结果将结果集封装为map集合,
String sql = \"select * from emp\
queryForList():查询结果将结果集封装为list集合
query的参数:RowMapper * 一般我们使用BeanPropertyRowMapper实现类。可以完成数据到JavaBean的自动封装 * new BeanPropertyRowMapper<类型>(类型.class)
用户信息查询
query():查询结果,将结果封装为JavaBean对象
一般用于聚合函数的查询用户登陆验证
String sql = \"select count(id) from emp\
queryForObject:查询结果,将结果封装为对象
4、在Dao中调用JdbcTemplate的方法来完成CRUD的操作
使用步骤
比如抽取这段每个Dao重复的代码private JdbcTemplate template;public void setTemplate(JdbcTemplate template){ this.template=template;}
JdbcDaoSupport是spring框架为我们提供的一个类,该类中定义了一个JdbcTemplate对象,我们可以直接获取使用,自己就不需要配置JdbcTemplate但是要想创建该对象,需要为其配置提供一个数据源dataSource
配置了dataSource 就会调用JdbcDaoSupport中的setDataSource方法,该方法会创建一个JdbcTemplate对象,具体看源码
让dao继承JdbcDaoSupport
注意:使用注解时不能继承JdbcDaoSupport了需要自己定义private JdbcTemplate template,因为jar包中我们无法使用注解
多个Dao间抽取BaseCode
Spring JDBC
核心控制器路径,此处的url-pattern如果是/则指的是除jsp文件以外的所有请求都包含,/*则包含jsp
核心控制器创建时机
核心控制器需要的配置文件
配置核心控制器
当服务器启动时,该监听器会通过配置文件来初始化spring容器,实现ioc
如果想通过配置监听来实现ioc,需要配下方的配置全局参数
配置监听器
该参数指向spring配置文件(该配置文件用于整合spring、mybatis),监听器会加载该配置文件,将配置文件中的数据源、对象以及mapper扫描器创建
配置全局参数
在web.xml中配置
mybatis.xml(可有可无),一般在该文件下配置settings和typeAliases,不过在配置sqlFactoryFactoryBean时也可以配置别名
数据源(druid)
数据源
<property name=\"typeAliasesPackage\" value=\"com.wxs.entity\">
别名
在配置sqlSession工厂时,通过property标签,让name值为mapperLocationsvalue值为classpath:com/wxs/mapper,这里需要使用斜线
用这种方式可以扫描项目下任意路径,可以解决mapper映射器文件和接口不在同意路径下的问题
配置mapper扫描器
sqlSessionFactory
<bean class=\"org.mybatis.spring.mapper.MapperScannerConfigurer\">
在该bean标签下配置sqlSessionFactoryBean,因为mapper接口的底层还是需要由sqlSession得到的
配置需要扫描的包
mapper扫描器
applicationContext-dao.xml
持久层(dao)
事务
包扫描器(主要针对@Service注解)
applicationContext-service.xml
业务层
配置处理器适配器、处理器映射器最新驱动
<mvc:annotation-driven/>
注解驱动版本
包扫描器,主要针对@Controller注解
以setter方式注入前缀和后缀
异常处理器,文件解析器,拦截器
springmvc.xml
web层(有mvc支持)
spring容器(配置文件)与springmvc容器(配置文件)是父子容器关系在这两个容器中都只能出现一个<context:property-placeholder location=\"\">标签加载文件,且子容器可以访问父容器加载到的配置文件,而父容器不能访问子容器加载的文件
***父子容器关系
ssm整合
Spring是一个轻量级的IOC和AOP容器的开源框架
Spring提倡以最少侵入(可以理解为耦合度)的方式来管理应用中的代码
子主题
Spring体系结构
什么是Spring
控制反转
控制:对对象的创建和管理
反转:对对象的控制由程序员转变为框架
概念
让spring来管理对象
核心目的
单例
降低耦合(类与类之间的依赖关系)
优点
不管service还是dao一般不会有类成员,不会有线程安全问题,选择使用单例模式创建既然是单例模式创建,采用立即加载创建对象就行
单例对象适用AplicationContext在构建核心容器时,创建对象采用的是立即加载的方式,即配置文件一读取完,立马创建对象
多例对象适用BeanFactory在构建核心容器时,创建对象采用的是延迟加载方式,即什么时候通过Id获取对象getBean(id),什么时候创建
顶层接口BeanFactory和ApplicationContext的区别
加载类路径下的配置文件
ClassPathXmlApplicationContext
加载磁盘任意位置的配置文件
FileSystemXmlApplicationContext
用于使用新注解+配置类的方式代替xml配置文件时
AnnotationConfigApplicationContext
ApplicationContext在构建核心容器是,创建对象采用的是立即加载
ApplicationContext常用实现类
IoC核心容器
在spring配置文件中用bean标签配置
创建的对象名
id
需要被管理的类的全路径
class
bean标签的属性
使用默认构造函数创建
条件:需要工厂类,这个工厂类中需要有普通方法
<bean id=\"factory\" class=\"com.google.factory.BeanFactory\" />
<bean id=\"car\" factory-bean=\"factory\" factory-method=\"普通方法名\">
配置文件语法
需要先创建工厂对象再调用工厂中的普通方法
spring管理实例工厂-使用实例工厂的方法创建对象
条件:需要工厂类,该工厂类中需要有静态方法
<bean id=\"factory\" class=\"com.wxs.factory.BeanFactory\" factory-method=\"静态方法名\" />
当用spring容器调用getBean方法时会创建工厂类对象,并执行工厂类中的方法返回需要的对象并放入spring容器中
spring管理静态工厂-使用静态工厂的方法创建对象
IOC实例化Bean对象三种方式
实例化Bean的三种方式
id属性:用来给对象命名
单例(默认值)
只要配置文件被加载,就会创建对象,创建的对象放在spring容器中,这个容器底层为map集合,key为bean标签的id值,value为这个对象
当调用容器的getBean方法的时候,总是获取到唯一的实例
service/dao需要单例模式
singleton
多例
当配置文件加载的时候不创建对象,当调用容器的getBean方法时,创建对象并返回,调用一次getBean则创建一次
action适合多例
proyotype
作用于web应用的请求范围
作用于web应用的会话范围
作用于集群环境的会话范围(全局范围)
globle-session
bean作用范围:scope属性
一个应用只有一个对象的实例。它的作用范围就是整个引用。生命周期:对象出生:当应用加载,创建容器时,对象就被创建了。对象活着:只要容器在,对象一直活着。对象死亡:当应用卸载,销毁spring容器时,对象就被销毁
单例对象:scope=\"singleton\"
每次访问对象时,都会重新创建对象实例。生命周期:对象出生:当使用对象时,创建新的对象实例。对象活着:只要对象在使用中,就一直活着。对象死亡:当对象长时间不用时,被 java 的GC机制回收
多例对象:scope=\"prototype\"
bean生命周期
bean标签:在配置文件中用bean标签配置一个类
条件:必须要有构造器
index:指定参数在构造函数参数列表的索引位置
type:指定参数在构造函数中的数据类型
常用:name:属性名
=======上面三个都是找给谁赋值,下面两个指的是赋什么值的=======
value:值,针对基本类型和Stirng
ref:针对其他bean类型,也就是说,必须得是在配置文件中配置过的bean
bean标签下<constructor-arg>标签
不常用
有参构造器注入
条件:属性必须有setter方法
name:属性名(不是变量名而是set方法小写的那个名字)
value:属性值,针对基本类型和String类型
ref:针对对象类型,指向的是bean标签的id属性的值
bean标签下<property>标签
setter注入(常用)
list类型语法
set类型
数组类型与list类型类似只是没有ref标签
array类型
<bean id=\"empService\" class=\"com.google.service.EmpService\"> <property name=\"list\"> <map> <entry key=\"\" value=\"\"></entry> </map> </property></bean>
map类型
<bean id=\"empService\" class=\"com.google.service.EmpService\"> <property name=\"p\"> <props> <prop key=\"\" >value值只能写标签体里</prop> </props> </property></bean>
properties类型
list、array、set
props、map
结构相同,标签可以互换
复杂注入(集合注入)
<bean id=\"empService\" class=\"com.wxs.service.EmpService\"> <property name=\"list\"> <list> <value>基本类型和String类型</value> <ref bean=\"对象类型\"></ref> </list> </property></bean>
条件:需要在配置文件中导入p的命名空间(spring提供的),底层还是set方式,所以属性也必须有setter方法
p名称空间注入
DI(依赖注入)的方式
专门用于给list集合类型的成员变量赋初始值
<bean id=\"empService\" class=\"com.google.service.EmpService\"> <property name=\"list\"> <list> <value>11</value> </list> </property></bean>
格式
property子标签<list>
手动配置(纯XML的IOC配置)
半自动配置方式主要是将类与类之间的依赖关系用注解的方式实现
类的对象还是需要手动配置,但类的依赖关系用注解@Autowired自动实现,例如A类中引用了B类,在配置文件中用bean标签配置A,在A中用注解标记引用的B
***注意:Spring框架为了效率,默认在扫描类的时候不会扫描注解,所以默认情况下只加Autowired注解是无法自动注入的,需要在配置文件用<context:annotation-config/>进行配置
半自动配置方式
@Component:无法划分类的时候
@Repository:一般用于持久层
@Service:业务层
@Controller:控制层/表现层(springmvc替代servlet)
====以上四个注解没有区别,只是用于不同场景====
@Scope:定义类的单例多例
bean作用范围
指定初始化方法
@PostConstruct
指定销毁方法
@PreDestory
生命周期(了解)
四个实例化对象的注解
属性值value:指定bean的id。
该注解由Spring框架提供
自动按照类型注入,如果找不到就是没有,如果找到多个再按照变量名匹配,如果变量名不匹配最后报错解决方式是搭配Qualifier注解指明适用哪个注解
@Qualifier
@Autowired
该注解由JDK提供
先按名字去找,第一种是name属性配置名字@Resource(name = \"名字\"),如果没有指定名字则把变量名当作要寻找的属性名,如果再找不到,最后按类型去找
@Resource
针对基本数据类型和String类型,且可以使用Spring中SqEl(Spring中的el表达式)${表达式}
@Value
三个依赖注入的注解
在类上用@Component注解标记,类中的依赖关系用@Autowired注解标记
在配置文件中用<context:component-scan base-package=\"com.google\" />配置需要扫描的包
在全自动配置方式中,对于私有的成员变量,也无须提供setter方法,反射会自动打开访问权限强制访问
***注意:如果通过一个类型匹配到了多个实现类,则会报错,解决方式为在引用类型上添加@Qualifier(\"\")注解指明需要的类
spring新注解(配置我们无法修改的类和配置扫描注解的类路径)
全自动配置(纯注解的IOC配置)
IOC三种开发方式
通过IO读取配置文件
利用反射创建对象:class.forName(配置文件中的全路径名)
如果是全自动模式,则通过IO读取配置文件读到的是包,然后再通过IO去扫描这个包下所有的类(包括子包)扫描的类如果由Component注解标记,则创建该类对象,如果没有,则忽略
重点是反射+IO
如何创建对象
扫描所有成员变量,如果成员变量带有自动注入注解,则从自己容器中寻找要注入的对象,利用反射对其进行注入,如果找到相应对象,暴力破解直接赋值,如果没找到,则报错
如何管理依赖关系
IOC
程序的入口为main
junit内部集成了一个main方法
当执行时,会利用反射判断该测试类有没有被@Test标注的方法
如果有,.invoke执行该方法
junit单元测试中没有main方法也能执行
在执行测试方法的时候,junit根本不知道我们是否使用了框架,所以在执行的时候根本不会为我们通过配置文件或者配置类来创建spring容器
junit不会管我们是否用框架
所以,在用junit测试的时候根本没有ioc容器,就算使用Autowired方法也不会有效果
在spring下junit的问题
导入spring整合junit的jar包--->spring-test.jar
使用junit提供的一个注解,把原有的main方法替换了,替换成spring自己的main@RunWith(SpringJUnit4ClassRunner.class)
告知spring运行器,spring和ioc创建是基于xml还是注解,并说明位置用@ContextConfiguration--->locations属性:指定xml文件位置,加上classpath关键字,表示该文件在类路径下 classes属性:指定配置类所在位置
代码
整合思路
当我们用spring5.x版本的时候,要求junit版本在4.12及以上版本
Spring整合junit
开发效率较高
每次请求都是整个页面刷新,当页面数据量大,用户设备老旧或者网速较差,会出现页面卡顿问题以至于交互效果较差
执行效率与交互效果低
如果有多个前端页面例如手机版、电脑版、iPad版,那得写多套控制层,较难
不灵活,解决多端变化问题较难
jsp开发模式
后台一律响应数据(json格式)而不响应页面,前端利用前端语言和后台的网络接口进行接收数据和显示
只需要写一套后台,不同前端用不同方式与后台交互
灵活,易于解决多端变化问题
开发效率较低
缺点
前后端分离开发模式开发前需要先设计文档,规定后台与前端所需要接口和参数的标准格式,以便于前后端同时开发且不容易出现前端调用后台接口出问题的情况
协议相同、ip相同、端口号相同
同源
做一个假网站,里面用 iframe 嵌套一个银行网站 http://mybank.com。
把 iframe 宽高啥的调整到页面全部,这样用户进来除了域名,别的部分和银行的网站没有任何差别。
这时如果用户输入账号密码,我们的主网站可以跨域访问到 http://mybank.com 的 dom 节点,就可以拿到用户的账户密码了。
DOM 同源策略:禁止对不同源页面 DOM 进行操作。这里主要场景是 iframe 跨域的情况,不同域名的 iframe 是限制互相访问的。
XMLHttpRequest 同源策略:禁止使用 XHR 对象向不同源的服务器地址发起 HTTP 请求。
同源策略
response.setHeader(\"Access-Control-Allow-Origin\
request.getHeader(\"Origin\")
该服务器路径可以通过请求对象动态获取
在后端设置响应头
在每个Controller类上加@CrossOrigin注解,该注解允许请求服务器默认为*
但是当前端设置为允许跨域携带参数后不允许将跨域访问路径设为*,虽然该注解可以设置路径,但需要在每个注解中设置跨域请求服务器路径,所以该方式不太方便
或者通过注解设置
在mvc.xml配置文件中配置拦截器
将该拦截器设置在所有拦截器的最上方,所有请求来之后都先被该拦截器拦截
在拦截器类中为response设置响应头response.setHeader(\"Access-Control-Allow-Origin\
通过拦截器设置
1. 设置后台允许接受跨域请求
在ajax请求中设置属性
在前端页面设置xhr对象的属性
XHR原生对象的withCredentials是用于跨域请求的,默认为false如果想要跨域请求并携带数据则需要将其打开
***在这种可携带数据的跨域模式下不可以设置为*
2. 设置前端允许跨域请求携带数据
在拦截器类中设置响应头
response.setHeader(\"Access-Control-Allow-Credentials\
3. 后台允许跨域请求携带数据
解决方案
跨域问题跨域带数据
前后端分离
开发模式
Spring5新特性(了解)
Spring
轻量级和重量级:轻量级是相对于重量级而言的,轻量级一般就是非入侵性的、所依赖的东西非常少、资源占用非常少、部署简单等等,其实就是比较容易使用,而重量级正好相反。非侵入式设计:从框架的角度可以理解为:无需继承框架提供的任何类这样我们在更换框架时,之前写过的代码几乎可以继续使用。
0 条评论
回复 删除
下一页