- 大佬总结
- 0、Spring常用注解
- 0.1、SpringBootController里面的用法
- 0.1.1、SpringBoot 中常用注解@Controller/@RestController/@RequestMapping/@SpringBootApplication介绍
- 0.1.2、@SpringBootApplication
- 0.1.3、@RequestMapping与@GetMapping和@PostMapping等新注释
- 0.1.4、@PathVariable注解使用
- 0.1.5、@RequestParam注解使用
- 0.2、Spring Boot 自定义配置
- 0.2.1spring的@Value注解和@ConfigurationProperties注解使用
- 0.2.2 Spring注解@Component、@Repository、@Service、@Controller区别
- 0.2.2.2@Repository的作用?
- 0.2.2.3 @component
- 0.2.2.4 @Autowired用法
- 0.2.2.5 对@Reference 、@Resource和@Autowired的简单理解
- @Slf4j
- 0.3、 spring注解@Service注解的使用
- 1、IOC
- 1.1、IOC简介
- 为什么叫控制反转
- 1.2、 IOC的主要实现方式
- 依赖注入
- 1.2.1、 IoC容器
- 1.2.2 、依赖注入
- 1.2.2.1、基于注解注入方式
- @Autowired与@Resource区别
- 1.2.2.2、属性setter注入
- 1.2.2.3、静态工厂方式实例化
- 1.2.2.4、实例工厂实例化
- IoC 解决了什么问题
- **面试怎么回答:**
- 2、 AOP
- 2.1、AOP简单理解
- 2.2、 AOP涉及名词
- AOP 解决了什么问题
- AOP 为什么叫面向切面编程
- Spring AOP 和 AspectJ AOP 有什么区别?
- 3、SpringMVC:
- Spring框架用了那些设计模式?
- DAO层,Service层,Controller层、View层
(面试必备)超详细Spring IOC、AOP、事务解析及其案例
0、Spring常用注解- Spring常用注解
在具体介绍IOC和AOP之前,我们先简要说明下Spring常用注解
0.1、SpringBootController里面的用法 0.1.1、SpringBoot 中常用注解@Controller/@RestController/@RequestMapping/@SpringBootApplication介绍@Controller/@RestController/@RequestMapping介绍
0.1.2、@SpringBootApplication声明这是一个Springboot的应用
0.1.3、@RequestMapping与@GetMapping和@PostMapping等新注释@RequestMapping与@GetMapping和@PostMapping
0.1.4、@PathVariable注解使用@PathVariable注解使用
0.1.5、@RequestParam注解使用@RequestParam注解使用
0.2、Spring Boot 自定义配置在 SpringBoot 的核心配置文件中,除了使用内置的配置项之外,我们还可以在自定义配
置,然后采用如下注解去读取配置的属性值
spring的@Value注解使用
@ConfigurationProperties
0.2.2 Spring注解@Component、@Repository、@Service、@Controller区别Spring注解@Component、@Repository、@Service、@Controller区别
0.2.2.2@Repository的作用?@Repository的作用?
@Repository的作用
0.2.2.3 @component@component
@component
@Autowired 的作用是什么?
0.2.2.5 对@Reference 、@Resource和@Autowired的简单理解对@Reference 、@Resource和@Autowired的简单理解
@Slf4j@Slf4j
0.3、 spring注解@Service注解的使用spring注解@Service注解的使用
1、@Controller:用于标注控制器层组件
2、@Service:用于标注业务层组件
3、@Component : 用于标注这是一个受 Spring 管理的组件,组件引用名称是类名,第一个字母小写。可以使用@Component(“beanID”) 指定组件的名称
4、@Repository:用于标注数据访问组件,即DAO组件
5、@Bean:方法级别的注解,主要用在@Configuration和@Component注解的类里,@Bean注解的方法会产生一个Bean对象,该对象由Spring管理并放到IoC容器中。引用名称是方法名,也可以用@Bean(name = “beanID”)指定组件名
6、@Scope(“prototype”):将组件的范围设置为原型的(即多例)。保证每一个请求有一个单独的action来处理,避免action的线程问题。
由于Spring默认是单例的,只会创建一个action对象,每次访问都是同一个对象,容易产生并发问题,数据不安全。
7、@Autowired:默认按类型进行自动装配。在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。
8、@Resource:默认按名称进行自动装配,当找不到与名称匹配的Bean时会按类型装配。
简单点说,就是,能够明确该类是一个控制器类组件的,就用@Controller;能够明确是一个服务类组件的,就用@Service;能够明确该类是一个数据访问组件的,就用@Repository;不知道他是啥或者不好区分他是啥,但是就是想让他动态装配的就用@Component。
@Controller、@Service、@Component、@Repository都是类级别的注解,如果一个方法也想动态装配,就用@Bean。
当我们想按类型进行自动装配时,就用@Autowired;当我们想按名称(beanID)进行自动装配时,就用@Resource;当我们需要根据比如配置信息等来动态装配不同的组件时,可以用getBean(“beanID”)。
到这里,如果对这些注解,或是自动装配不太理解,可以继续往下,看完 控制反转(IoC) 内容后再回来理解这里的内容。
1、IOC 1.1、IOC简介IOC(Inverse of Control):控制反转,也可以称为依赖倒置。
所谓依赖,从程序的角度看,就是比如A要调用B的方法,那么A就依赖于B,反正A要用到B,则A依赖于B。所谓倒置,你必须理解如果不倒置,会怎么着,因为A必须要有B,才可以调用B,如果不倒置,意思就是A主动获取B的实例:B b = new B(),这就是最简单的获取B实例的方法(当然还有各种设计模式可以帮助你去获得B的实例,比如工厂、Locator等等),然后你就可以调用b对象了。所以,不倒置,意味着A要主动获取B,才能使用B;到了这里,就应该明白了倒置的意思了。倒置就是A要调用B的话,A并不需要主动获取B,而是由其它人自动将B送上门来。
IoC (Inversion of control )控制反转/反转控制。它是一种思想不是一个技术实现。描述的是:Java 开发领域对象的创建以及管理的问题。
例如:现有类 A 依赖于类 B
传统的开发方式 :往往是在类 A 中手动通过 new 关键字来 new 一个 B 的对象出来 使用 IoC 思想的开发方式 :不通过 new 关键字来创建对象, 而是通过 IoC 容器(Spring 框架) 来帮助我们实例化对象。我们需要哪个对象,直接从 IoC 容器里面过去即可。
从以上两种开发方式的对比来看:我们 “丧失了一个权力” (创建、管理对象的权力),从而也得到了一个好处(不用再考虑对象的创建、管理等一系列的事情)
为什么叫控制反转控制 :指的是对象创建(实例化、管理)的权力
反转 :控制权交给外部环境(Spring 框架、IoC 容器)
控制反转,简单点说,就是创建对象的控制权,被反转到了Spring框架上。 通常,我们实例化一个对象时,都是使用类的构造方法来new一个对象, 这个过程是由我们自己来控制的,而控制反转就把new对象的工交给了Spring容器。
形象的举例就是:
通常情况下,假如你有一天在家里口渴了,要喝水,那么你可以到你小区的小卖部去,告诉他们,你需要一瓶水,然后小卖部给你一瓶水!这本来没有太大问题,关键是如果小卖部很远,那么你必须知道:从你家如何到小卖部;小卖部里是否有你需要的水;你还要考虑是否开着车去;等等等等,也许有太多的问题要考虑了。也就是说,为了一瓶水,你还可能需要依赖于车等等这些交通工具或别的工具,问题是不是变得复杂了?那么如何解决这个问题呢?
解决这个问题的方法很简单:小卖部提供送货上门服务,凡是小卖部的会员,你只要告知小卖部你需要什么,小卖部将主动把货物给你送上门来!这样一来,你只需要做两件事情,你就可以活得更加轻松自在:
第一:向小卖部注册为会员。
第二:告诉小卖部你需要什么。
这和Spring的做法很类似!Spring就是小卖部,你就是A对象,水就是B对象
第一:在Spring中声明一个类:A
第二:告诉Spring,A需要B
IOC的主要实现方式有依赖注入。
依赖注入依赖注入,组件不做定位查询,只提供标准的Java方法让容器去决定依赖关系。容器全权负责组件的装配,把符合依赖关系的对象通过Java Bean属性或构造方法传递给需要的对象。
1.2.1、 IoC容器IoC容器:具有依赖注入功能的容器,可以创建对象的容器。IoC容器负责实例化、定位、配置应用程序中的对象并建立这些对象之间的依赖。
1.2.2 、依赖注入DI,英文全称,Dependency Injection,意为依赖注入。
依赖注入:由IoC容器动态地将某个对象所需要的外部资源(包括对象、资源、常量数据)注入到组件(Controller, Service等)之中。简单点说,就是IoC容器会把当前对象所需要的外部资源动态的注入给我们。
Spring依赖注入的方式主要有四个,基于注解注入方式、set注入方式、构造器注入方式、静态工厂注入方式。推荐使用基于注解注入方式,配置较少,比较方便。
1.2.2.1、基于注解注入方式服务层代码
@Service public class AdminService { //code }
控制层代码
@Controller @Scope("prototype") public class AdminController { @Autowired private AdminService adminService; //code }@Autowired与@Resource区别
@Autowired与@Resource都可以用来装配Bean,都可以写在字段、setter方法上。他们的区别是:
@Autowired默认按类型进行自动装配(该注解属于Spring),默认情况下要求依赖对象必须存在,如果要允许为null,需设置required属性为false,例:@Autowired(required=false)。如果要使用名称进行装配,可以与@Qualifier注解一起使用。
@Autowired @Qualifier("adminService") private AdminService adminService;
@Resource默认按照名称进行装配(该注解属于J2EE),名称可以通过name属性来指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行装配;如果注解写在setter方法上,默认取属性名进行装配。当找不到与名称相匹配的Bean时,会按照类型进行装配。但是,name属性一旦指定,就只会按照名称进行装配。
@Resource(name = "adminService") private AdminService adminService;
除此之外,对于一些复杂的装载Bean的时机,比如我们需要根据配置装载不同的Bean,以完成不同的 *** 作,可以使用getBean(“beanID”)的方式来加载Bean。
通过BeanID加载Bean方法如下:
@Component public class BeanUtils implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) { if (BeanUtils.applicationContext == null) { BeanUtils.applicationContext = applicationContext; } } public static ApplicationContext getApplicationContext() { return applicationContext; } public static Object getBean(String id) throws Exception { try { return applicationContext.containsBean(id) ? applicationContext.getBean(id) : null; } catch (BeansException e) { e.printStackTrace(); throw new Exception("not found bean id: " + id); } } }
我们在需要装载Bean的地方调用该方法即可
public class baseController { protected IService loadService(String id) throws Exception { IService iService = (IService) BeanUtils.getBean(id); if (iService != null) { return iService; } else { throw new Exception("加载Bean错误"); } } }1.2.2.2、属性setter注入
//创建类A public class A { public A() { System.out.println("正在初始化类A,调用无参构造器A。。。"); } public void print() { System.out.println("调用了类A的print方法。。。"); } } //创建类B public class B { private A a; public void setA(A a) { this.a = a; } public void print() { a.print(); } } //配置Beans.xml//测试 @Test public void test() { B b = (B) context.getBean("b"); b.print(); }
构造构造器注入
//配置Beans.xml1.2.2.3、静态工厂方式实例化//测试 @Test public void test() { B b = (B) context.getBean("b"); b.print(); }
//创建工厂类 public class MyBeanFactory { public static A createCoffer() { return new A(); } } //配置Beans.xml1.2.2.4、实例工厂实例化//测试 @Test public void test() { A a = (A) context.getBean("a"); }
//创建工厂类 public class MyBeanFactory { public MyBeanFactory() { System.out.println("A工厂实例化中。。。"); } public A createBean() { return new A(); } } //配置Beans.xmlIoC 解决了什么问题//测试 @Test public void test() { A a = (A) context.getBean("a"); }
IoC 的思想就是两方之间不互相依赖,由第三方容器来管理相关资源。这样有什么好处呢?
1、对象之间的耦合度或者说依赖程度降低; 2、资源变的容易管理;比如你用 Spring 容器提供的话很容易就可以实现一个单例。
例如:现有一个针对 User 的 *** 作,利用 Service 和 Dao 两层结构进行开发
在没有使用 IoC 思想的情况下,Service 层想要使用 Dao 层的具体实现的话,需要通过 new 关键字在UserServiceImpl 中手动 new 出 IUserDao 的具体实现类 UserDaoImpl(不能直接 new 接口类)。
很完美,这种方式也是可以实现的,但是我们想象一下如下场景:
开发过程中突然接到一个新的需求,针对对IUserDao 接口开发出另一个具体实现类。因为 Server 层依赖了IUserDao的具体实现,所以我们需要修改UserServiceImpl中 new 的对象。如果只有一个类引用了IUserDao的具体实现,可能觉得还好,修改起来也不是很费力气,但是如果有许许多多的地方都引用了IUserDao的具体实现的话,一旦需要更换IUserDao 的实现方式,那修改起来将会非常的头疼。
使用 IoC 的思想,我们将对象的控制权(创建、管理)交有 IoC 容器去管理,我们在使用的时候直接向 IoC 容器 “要” 就可以了
IOC是spring的两大核心概念之一,IOC给我们提供了一个IOCbean容器,这个容器会帮我们自动去创建对象,不需要我们手动创建,IOC实现创建的通过DI(Dependency Injection 依赖注入),我们可以通过写Java注解代码或者是XML配置方式,把我们想要注入对象所依赖的一些其他的bean,自动的注入进去,他是通过byName或byType类型的方式来帮助我们注入。正是因为有了依赖注入,使得IOC有这非常强大的好处,解耦。
可以举个例子,JdbcTemplate 或者 SqlSessionFactory 这种bean,如果我们要把他注入到容器里面,他是需要依赖一个数据源的,如果我们把JdbcTemplate 或者 Druid 的数据源强耦合在一起,会导致一个问题,当我们想要使用jdbctemplate必须要使用Druid数据源,那么依赖注入能够帮助我们在Jdbc注入的时候,只需要让他依赖一个DataSource接口,不需要去依赖具体的实现,这样的好处就是,将来我们给容器里面注入一个Druid数据源,他就会自动注入到JdbcTemplate如果我们注入一个其他的也是一样的。比如说c3p0也是一样的,这样的话,JdbcTemplate和数据源完全的解耦了,不强依赖与任何一个数据源,在spring启动的时候,就会把所有的bean全部创建好,这样的话,程序在运行的时候就不需要创建bean了,运行速度会更快,还有IOC管理bean的时候默认是单例的,可以节省时间,提高性能。
2、 AOP 2.1、AOP简单理解AOP:即面向切面编程
面向切面编程(AOP)就是纵向的编程。比如业务A和业务B现在需要一个相同的 *** 作,传统方法我们可能需要在A、B中都加入相关 *** 作代码,而应用AOP就可以只写一遍代码,A、B共用这段代码。并且,当A、B需要增加新的 *** 作时,可以在不改动原代码的情况下,灵活添加新的业务逻辑实现。
能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
Spring AOP是基于动态代理:如果代理类是实现了接口的类型,那么Spring将会用jdk的Proxy,如果代理类没有实现接口,那么将会使用CJlib的动态代理生成代理类的子类,其底层是使用了字节码 *** 作(ASM)技术。
在实际开发中,比如商品查询、促销查询等业务,都需要记录日志、异常处理等 *** 作,AOP把所有共用代码都剥离出来,单独放置到某个类中进行集中管理,在具体运行时,由容器进行动态织入这些公共代码。
AOP主要一般应用于签名验签、参数校验、日志记录、事务控制、权限控制、性能统计、异常处理等。
2.2、 AOP涉及名词切面(Aspect):共有功能的实现。如日志切面、权限切面、验签切面等。在实际开发中通常是一个存放共有功能实现的标准Java类。当Java类使用了@Aspect注解修饰时,就能被AOP容器识别为切面。
通知(Advice):切面的具体实现。就是要给目标对象织入的事情。以目标方法为参照点,根据放置的地方不同,可分为前置通知(Before)、后置通知(AfterReturning)、异常通知(AfterThrowing)、最终通知(After)与环绕通知(Around)5种。在实际开发中通常是切面类中的一个方法,具体属于哪类通知,通过方法上的注解区分。
连接点(JoinPoint):程序在运行过程中能够插入切面的地点。例如,方法调用、异常抛出等。Spring只支持方法级的连接点。一个类的所有方法前、后、抛出异常时等都是连接点。
切入点(Pointcut):用于定义通知应该切入到哪些连接点上。不同的通知通常需要切入到不同的连接点上,这种精准的匹配是由切入点的正则表达式来定义的。
比如,在上面所说的连接点的基础上,来定义切入点。我们有一个类,类里有10个方法,那就产生了几十个连接点。但是我们并不想在所有方法上都织入通知,我们只想让其中的几个方法,在调用之前检验下入参是否合法,那么就用切点来定义这几个方法,让切点来筛选连接点,选中我们想要的方法。切入点就是来定义哪些类里面的哪些方法会得到通知。
目标对象(Target):那些即将切入切面的对象,也就是那些被通知的对象。这些对象专注业务本身的逻辑,所有的共有功能等待AOP容器的切入。
代理对象(Proxy):将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象本身业务逻辑加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。目标对象被织入共有功能后产生的对象。
织入(Weaving):将切面应用到目标对象从而创建一个新的代理对象的过程。这个过程可以发生在编译时、类加载时、运行时。Spring是在运行时完成织入,运行时织入通过Java语言的反射机制与动态代理机制来动态实现。
AOP 解决了什么问题通过上面的分析可以发现,AOP 主要用来解决:在不改变原有业务逻辑的情况下,增强横切逻辑代码,根本上解耦合,避免横切逻辑代码重复。
AOP 为什么叫面向切面编程切 :指的是横切逻辑,原有业务逻辑代码不动,只能 *** 作横切逻辑代码,所以面向横切逻辑
面 :横切逻辑代码往往要影响的是很多个方法,每个方法如同一个点,多个点构成一个面。这里有一个面的概念
Spring AOP 和 AspectJ AOP 有什么区别?Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码 *** 作(Bytecode Manipulation)。
Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,
如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比Spring AOP 快很多。
3、SpringMVC:MVC是一种设计模式,M(模型),V(视图),C(控制)分层开发。在SpringMVC中我们一般将项目分为四层,业务处理层(Service),数据库 *** 作层(Dao),实体层(Entity),控制层(Controller)。
SpringMVC的工作原理:
在SpringMVC中有一个重要的中央控制器dispatcherServlet,或者叫做中央分发器,他负责接收前端请求,返回结果映射。其步骤如下:
1、浏览器发送请求,tomcat接收到请求之后传给了dispatcherServlet。 2、dispatcher传给了HandlerMapping处理器映射器将将会根据url解析出映射的handler。 3、HandlerAdapter处理器适配器将会调用映射的handler返回一个ModelAndView对象,包括一个Model和View对象。Model是返回的数据,View是逻辑上的View。 4、ViewResover视图解析器将会解析根据逻辑的VIew解析出实际的View。 5、dispatcherServlet将Model传给View。 6、dispatcherServlet返回View给浏览器。Spring框架用了那些设计模式?
工厂设计模式 : Spring使用工厂模式通过 BeanFactory、ApplicationContext 创建 bean 对象。
代理设计模式 : Spring AOP 功能的实现。
单例设计模式 : Spring 中的 Bean 默认都是单例的。
模板方法模式 : Spring 中 jdbcTemplate、hibernateTemplate 等以 Template 结尾的对数据库 *** 作的类,它们就使用到了模板模式。
包装器设计模式 : 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。
观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。
适配器模式 :Spring AOP 的增强或通知(Advice)使用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller。
DAO层,Service层,Controller层、View层
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)