赞
踩
BeanFactory 是 Bean 的工厂, ApplicationContext 的父类,IOC 容器的核心,负责生产和管理 Bean 对象。
FactoryBean 是 Bean,可以通过实现 FactoryBean 接口定制实例化 Bean 的逻辑,通过代理一个Bean对象,对方法前后做一些操作。
软件系统在没有引入IOC容器之前,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B。控制权都在自己手上。
软件系统在引入IOC容器之后,这种情形就完全改变了,由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。
IOC容器相当于第三方,让每一个对象之间没有了耦合关系,每个对象的工作全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器,所以,IOC容器成了整个系统的关键核心,它起到了一种类似“粘合剂”的作用,把系统中的所有对象粘合在一起发挥作用。
软件系统在没有引入IOC容器之前,对象A依赖于对象B,那么对象A在初始化或者运行到某一点的时候,自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B,控制权都在自己手上。
软件系统在引入IOC容器之后,这种情形就完全改变了,由于IOC容器的加入,对象A与对象B之间失去了直接联系,所以,当对象A运行到需要对象B的时候,IOC容器会主动创建一个对象B注入到对象A需要的地方。
当去掉IOC容器的时候,对象之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现A的时候,根本无须再去考虑B、C和D了,对象之间的依赖关系已经降低到了最低程度。
对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。
既然IOC是控制反转,那么到底是“哪些方面的控制被反转了呢?”
答案:“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)”。
缺点:
所谓依赖注入(Dependency Injection),即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。
面向切面编程,将系统按照功能分类,每一个类别就是一个“切面”
所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
AOP(Aspect-Oriented Programming),一般称为面向切面编程,作为面向对象的一种补充用于将那些与业务无关,但却对多个对象产生影响的公共行为,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。
Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理,如下图所示:
使用 AOP 之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使用即可,这样大大简化了代码量。我们需要增加新功能时也方便,这样也提高了系统扩展性。日志功能==、事务管理等等场景都用到了 AOP 。
面向对象:事物的抽象、降低耦合,提高维护性
面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们我们使用的就是面向对象了。
面向对象的三大特性:
1、封装
隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。
2、继承
提高代码复用性;继承是多态的前提。
3、多态
父类可以指向子类或具体实现类的实例对象。提高了程序的拓展性。
1、构造方法注入
构造方法注入是指在构造方法中注入属性或者对象来实现依赖注入,注入完成后直接通过this.username获取到值。
public class UserDaoImpl {
private String username;
public UserDaoImpl(String username) {
this.username = username;
}
}
2、set方法注入
set方法注入就是通过在类中实现get、set方法来实现属性或者对象的依赖注入,注入完成后直接通过getUsername()获取到值。
public class UserDaoImpl {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
3、自动装配
Spring提供了自动装配的功能,简化了我们的配置,自动装配默认是不打开的,常用的方式有两种:
byName:通过参数名自动装配
id为userService的的autowire被设置为byName后,IOC容器会通过名字来自动装配,发现UserService类中有个叫userDao的属性,然后看看IOC容器中有没有id为userDao的,如果有就装配进去。
<bean id="userDao" class="com.example.UserDao"></bean>
<bean id="userService" class="com.example.UserService" autowire="byName"/>
byType:通过参数类型自动装配
4、注解
@Autowired注解可以实现自动装配,只要在对应的属性上标记该注解,但是@Autowired注解只按照byType注入。
public class UserController {
@Autowired
private IUserService userService;
}
@Resource注解可以实现自动装配,它有两个重要属性name和type,name属性解析为bean的名字,type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
@Autowired注解和@Resource注解的作用相同,只不过==@Autowired按照byType注入==,如果@Autowired想使用名称可以结合@Qualifier注解进行使用。
声明 Spring Bean 的作用域,使用方法:
@Bean
@Scope("singleton")
public Person personSingleton() {
return new Person();
}
Spring 中的 Bean 默认是单例模式,Spring 框架并没有对单例 Bean 进行多线程的封装处理,因此默认的情况 Bean 并非是安全的,
自动导入对象到类中,被注入进的类同样要被 Spring 容器管理比如:Service 类注入到 Controller 类中。
@Service
public class UserService {
......
}
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
......
}
我们一般使用 @Autowired 注解让 Spring 容器帮我们自动装配 bean要想把类标识成可用于 @Autowired 注解自动装配的 bean 的类, 可以采用以下注解实现:
@RestController注解是@Controller和@ResponseBody的合集,表示这是个控制器 bean,并且是将函数的返回值直 接填入 HTTP 响应体中,是 REST 风格的控制器。
一般用来声明配置类,可以使用 @Component注解替代,不过使用@Configuration注解声明配置类更加语义化。
@PathVariable用于获取路径参数,@RequestParam用于获取查询参数。
如果我们请求的 url 是:/klasses/{123456}/teachers?type=web
那么我们服务获取到的数据就是:klassId=123456,type=web。
用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分并且Content-Type 为 application/json 格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上去。
使用 @Value("${property}") 读取比较简单的配置信息:
@Value("${wuhan2020}")
String wuhan2020;
@Service publicclass TestService1 { @Autowired private TestService2 testService2; @Async public void test1() { } } @Service publicclass TestService2 { @Autowired private TestService1 testService1; public void test2() { } }
首先,Spring 解决循环依赖有两个前提条件:
基于上面的问题,我们知道Bean的生命周期,本质上解决循环依赖的问题就是三级缓存,通过三级缓存提前拿到未初始化的对象。
创建对象A,实例化的时候把A对象工厂放入三级缓存,A注入的时候,发现依赖B,转而去实例化B。
再创建B,注入时发现依赖A,依次从一级缓存到三级缓存查询A,从三级缓存通过对象工厂拿到A,二就会进入二级缓存,此时B已经实例化好了,B就进入一级缓存。
继续创建A,顺利从一级缓存拿到实例化且初始化完成的对象B,A就会创建完成,删除二级缓存的A,同时把A放入到一级缓存。
编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。
声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。真正的数据库层的事务提交和回滚是通过binlog或者redo log实现的。
spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT
脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。
不可重复读 :是指在一个事务内,多次读同一数据。
幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。
前端控制器(DispatcherServlet) 接收请求,通过映射从 IoC 容器中获取对应的 Controller 对象和 Method 方法,在方法中进行业务逻辑处理组装数据,组装完数据把数据发给视图解析器,视图解析器根据数据和页面信息生成最终的页面,然后再返回给客户端。
客户端发送请求至前端控制器(DispatcherServlet)
前端控制器根据请求路径,进入对应的处理器
处理器调用相应的业务方法
处理器获取到相应的业务数据
处理器把组装好的数据交还给前端控制器
前端控制器将获取的 ModelAndView 对象传给视图解析器
(ViewResolver)
前端控制器获取到解析好的页面数据
前端控制器将解析好的页面返回给客户端
Spring MVC 的核心组件
DispatcherServlet:核心处理器(也叫前端控制器),负责调度其他组件的执行,可降低不同组件之间的耦合性,是整个 Spring MVC 的核心模块。接收请求、响应结果,相当于转发器
HandlerMapping:DispatcherServlet 是通过 HandlerMapping 将请求映射到不同的 Handler。根据请求的URL来查找Handler
HandlerInterceptor:处理器拦截器,是一个接口,如果我们需要做一些拦截处理,可以来实现这个接口。
ModelAndView:装载了模型数据和视图信息,作为 Handler 的处理结果,返回给 DispatcherServlet。
ViewResolver:视图解析器,DispatcherServlet 通过它将逻辑视图解析成物理视图,最终将渲染结果响应给客户端。
JavaBean 是 Java 语言中的一种可重用组件,JavaBean 的构造函数和行为必须符合特定的约定:这个类必须有一个公共的缺省构造函数;这个类的属性使用 getter/setter 来访问,其他方法遵从标准命名规范;这个类应是可序列化的。
当一个 POJO 可序列化,有一个无参的构造函数,它就是一个JavaBean。
在后端通过 (CORS,Cross-origin resource sharing) 来解决跨域问题,实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的请求规则
registry.addMapping("/api/**");
}
};
}
}
用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径。
value:指定 URL 请求的实际地址,用法:
@RequestMapping(value="/index");
method:指定请求的 method 类型,如 GET/POST/PUT/DELETE 等,用法:
@RequestMapping(value="/list",method=RequestMethod.POST);
params:指定请求参数中必须包含的参数名称,如果不存在该名称,则无
法调用此方法,用法:
@RequestMapping(value="/list",params={“name”,“age”})。
从请求参数中获取
@RequestMapping("/index")
@ResponseBody
public void index(HttpServletRequest request){
// do something
}
通过自动注入的方式
@Controller
public class HomeController{
@Autowired
private HttpServletRequest request; // 自动注入 request 对象
// do something
}
springBoot
Spring Boot 的核心思想是约定优于配置,让开发人员不需要配置任何 XML 文件,就可以像Maven 整合 Jar 包一样,整合并使用所有框架。
Stater 可以理解为启动器,它是方便开发者快速集成其他框架到 Spring 中的一种技术。比如,spring-boot-starter-web:Web 开发支持,mybatis-spring-boot-starter:MyBatis 框架支持
Spring Boot 在启动的时候会干这几件事情:
其实就是 Spring Boot 在启动的时候,按照约定去读取 Spring Boot Starter 的配置信息,再根据配置信息对资源进行初始化,并注入到 Spring 容器中。这样 Spring Boot 启动完毕后,就已经准备好了一切资源,使用过程中直接注入对应 Bean 资源即可
1、什么是自动装配
Spring Boot 中,我们直接引入一个 starter 即可。比如你想要在项目中使用 redis 的话,直接在项目中引入对应的 starter 即可。在业务层可以直接使用@Autowired 来注入RedisTemplate实例,这就说明 IOC 容器中已经存在了 RedisTemplate。这就是Springboot的自动装配机制。
案例中,并没有事先通过 XML 形式或者注解的形式把 RedisTemplate 注入到 IOC 容器中,
2、SpringBoot 是如何实现自动装配的?
springBoot 的核心注解 SpringBootApplication 。
1、@SpringBootConfiguration:标记当前类为配置类
@EnableAutoConfiguration:开启自动配置
@ComponentScan:扫描主类所在的同级包以及下级包里的Bean
最重要的是@EnableAutoConfiguration:是springboot实现自动化配置的核心注解,通过这个注解把spring应用所需的bean注入容器中
@EnableAutoConfiguration可以帮助SpringBoot应用将所有符合条件的配置都加载到当前SpringBoot创建并使用的IoC容器中;
通过@Import(AutoConfigurationImportSelector.class)导入的配置功能,AutoConfigurationImportSelector类中的方法,
SpringFactoriesLoader.loadFactoryNames()可以得到需要配置的class的类名集合,这个集合就是所有需要进行自动配置的类,但是 是否配置的关键在于META-INF/spring.factories文件中是否存在该配置信息。
SpringFactoriesLoader.loadFactoryNames()
扫描所有jar包类路径下 META‐INF/spring.factories
把扫描到的这些文件的内容包装成properties对象
从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中
2、@ComponentScan:由于@Service,@Repository, @Controller用来定义一个bean,@ComponentScan注解就是用来自动扫描被这些注解标识的类,最终生成ioc容器里的bean.
3、@Retention(RetentionPolicy.RUNTIME):该注解保留到哪个阶段。RUNTIME、SOURCE、CLASS
4、@SpringBootConfiguration:这个注解的作用与
@Configuration作用相同,都是用来声明当前类是一个配置类.可以通过@Bean注解生成IOC容器管理的bean。然后可以在其它类中注入使用(@Autowired)
自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖
@Conditional中
matches方法就像正则的那个类一样…应该是true注入,false不注入
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
使用exclusions标签来去掉某个dependency依赖中的某一个jar包或一堆jar包,exclusion中的jar包或者依赖的相关jar包都会被忽略,从而在两个dependency都依赖某个jar包时,可以保证只使用其中的一个。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.8.3.2</version>
<exclusions>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
<exclusion>
<artifactId>spring</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
MyBatis 首先加载 Mapper 配置和SQL 映射文件,通过创建会话工厂得到 SqlSession 对象,再执行 SQL 语句并返回操作信息。
传参:可以通过@Param(“key”)为Map集合指定键的名字
取参:
Dao 接口里的方法可以重载,但是Mybatis的XML里面的ID不允许重复。
Mybatis 的 Dao 接口可以有多个重载方法,但是多个接口对应的映射必须只有一个,否则启动会报错。
Dao 接口的工作原理是 JDK 动态代理,MyBatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象,代理对象 proxy 会拦截接口方法,转而执行MappedStatement所代表的 sql,然后将 sql 执行结果返回。
MyBatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内存分页,而非物理分页,可以在 sql 内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。
分页插件的基本原理是使用 MyBatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的 sql,然后重写 sql
select t._ from (select \* from student)t limit 0,10
limit start(页码)、pageSize(每页显示的条数)
limit (start-1)*pageSize,pageSize
查询第10条到第20条的数据的sql是:select * from table limit 10,10; ->对应我们的需求就是查询第二页的数据:select * from table limit (2-1)*10,10;
MyBatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能,MyBatis 提供了 9 种动态 sql 标签
trim|where|set|foreach|if|choose|when|otherwise|bind。
Authentication(认证) 是验证您的身份的凭据(例如用户名/用户 ID 和密码),通过这个凭据,系统存在你这个用户。
Authorization(授权) 发生在 Authentication(认证) 之后。比如有些特定资源只能具有特定权限的人才能访问比如 admin,有些对系统资源操作比如删除、添加、更新只能特定人才具有。
用户成功登陆系统,然后返回给客户端具有 SessionID 的 Cookie
当用户向后端发起请求的时候会把 SessionID 带上,这样后端就知道你的身份状态了。
假如我们部署了两份相同的服务 A,B,用户第一次登陆的时候 ,Nginx 通过负载均衡机制将用户请求转发到 A 服务器,此时用户的 Session 信息保存在 A 服务器。结果,用户第二次访问的时候 Nginx 将请求路由到 B 服务器,由于 B 服务器没有保存 用户的 Session 信息,导致用户需要重新进行登陆。
解决方案:
1、某个用户的所有请求都通过特性的哈希策略分配给同一个服务器处理。这样的话,每个服务器都保存了一部分用户的 Session 信息。服务器宕机,其保存的所有 Session 信息就完全丢失了。
2、每一个服务器保存的 Session 信息都是互相同步的,也就是说每一个服务器都保存了全量的Session信息 每当一个服务器的 Session 信息发生变化,我们就将其同步到其他服务器。这种方案成本太大,并且,节点越多时,同步成本也越高。
CSRF(Cross Site Request Forgery)一般被翻译为 跨站请求伪造。
Session 认证中 Cookie 中的 SessionId 是由浏览器发送到服务端的,借助这个特性,攻击者就可以通过让用户误点攻击链接,达到攻击效果。
但是,我们使用 Token 的话就不会存在这个问题,在我们登录成功获得 Token 之后,一般会选择存放在 localStorage (浏览器本地存储)中。然后我们在前端通过某些方式会给每个发到后端的请求加上这个 Token,这样就不会出现 CSRF 漏洞的问题。因为,即使有个你点击了非法链接发送了请求到服务端,这个非法请求是不会携带 Token 的,所以这个请求将是非法的。
我们知道 Session 信息需要保存一份在服务器端。这种方式会带来一些麻烦,比如需要我们保证保存 Session 信息服务器的可用性、不适合移动端(依赖 Cookie)等等。
JWT (JSON Web Token) 就是这种方式的实现,通过这种方式服务器端就不需要保存 Session 数据了,只用在客户端保存服务端返回给客户的 Token 就可以了,扩展性得到提升。
JWT 本质上就一段签名的 JSON 格式的数据。由于它是带有签名的,因此接收者便可以验证它的真实性。
JWT 由 3 部分构成:
OAuth 是一个行业的标准授权协议,主要用来授权第三方应用获取有限的权限。
OAuth 2.0 比较常用的场景就是第三方登录,当你的网站接入了第三方登录的时候一般就是使用的 OAuth 2.0 协议。
微信开放平台
必须是在微信客户端,引导微信用户访问下面文档指定的url。我们可以修改的仅仅是接口中重定向redirect_uri部分,可以重定向到我们自己开发的页面中。获取code
APPID:唯一标识,开发者ID
APPSECRET:开发者密码,
access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。access_token的有效期目前为2个小时。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。