- spring就是一个轻量级的控制反转(IOC)和面相切面编程(AOP)的框架。
环境搭建
maven导入依赖
org.springframework spring-webmvc 5.2.0.RELEASE org.springframework spring-jdbc 5.2.0.RELEASE
优点
spring是一个轻量级,非入侵式的框架。
控制反转(IOC),面相切面编程(AOP)
支持事务的处理
Ioc思想
有依赖就有耦合,伴随着工业级应用的规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖性关系,因此,架构师和设计师对于系统的分析和设计,将面临更大的挑战。对象之间耦合度过高的系统,必然会出现牵一发而动全身的情形。
首先,由于引入了IOC容器,现在A要用到B不是通过直接在A中new对象了,而是需要让IOC容器帮你从B中拿,IOC容器拿到过后再通过依赖注入(DI)注入进A中,这整个过程不再是A主动创建B对象了,而是A在被动接受IOC容器给A注入的B,这个对象是IOC容器通过反射创建的,控制权移交到了IOC容器那里。也就是说,对象A获得依赖对象B的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。
这个IOC容器就是降低耦合度的关键所在
XML创建映射
<?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">
<!--使用Spring创建对象,spring中称为beran
初始:类型 变量名 =new 类型();
id=变量名 class=new 的对象
property 给属性设一个值
-->
<bean id="hello2" class="com.wzs.pojo.hello">
<property name="str" value="Spring"/>
</bean>
</beans>
public class MyTest {
public static void main(String[] args) {
//获取spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.getStr();
}
}
IOC创建对象的方式
使用无参构造方法。
假设使用有参构造方法。
1.下标
<bean id="user" class="com.wzs.pojo.User">
<constructor-arg index="0" value="wzs"></constructor-arg>
</bean>
2.类型
<bean id="user" class="com.wzs.pojo.User">
<constructor-arg type="java.lang.String" value="wzs"></constructor-arg>
</bean>
3.参数名
<bean id="user" class="com.wzs.pojo.User">
<constructor-arg name="as" value="wzs"></constructor-arg>
</bean>
总结
在配置文件加载的时候,容器中管理的对象就已经初始化了。
什么是bean
Bean的中文含义是“豆子”,顾名思义JavaBean是一段Java小程序。JavaBean实际上是指一种特殊的Java类,它通常用来实现一些比较常用的简单功能,并可以很容易的被重用或者是插入其他应用程序中去。所有遵循一定编程原则的Java类都可以被称作JavaBean。
Spring配置
alais
<alias name="user" alias="user2"></alias>
bean
<!--
id:bean是唯一的标识符,对象名
class:bean对象对应的全限定名: 包名+类型
name:也是别名,可以取多个别名,alias只能取一个
-->
<bean id="user" class="com.wzs.pojo.hello" name="u1,u2">
</bean>
import
多人开发将分支包导入到一个总包
<import resource="beans1.xml"></import>
<import resource="beans2.xml"></import>
<import resource="beans3.xml"></import>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
依赖注入
构造器注入
set注入(重点)
依赖:bean对象的创建依赖于容器。
注入:bean对象中的所有属性
<bean id="address" class="com.wzs.pojo.Address"></bean>
<bean id="student" class="com.wzs.pojo.Student">
<!--普通值注入,value-->
<property name="name" value="韦智深"></property>
<!--bean注入,ref,引用-->
<property name="address" ref="address"/>
<!--数组注入,ref-->
<property name="books">
<array>
<value>红楼梦</value>
<value>西游记</value>
<value>水浒传</value>
</array>
</property>
<property name="hobbys">
<list>
<value>听歌</value>
<value>看剧</value>
</list>
</property>
<property name="card">
<map>
<entry key="身份证" value="1112331231"></entry>
<entry key="手机号" value="1304811245"></entry>
</map>
</property>
<property name="games">
<set>
<value>lol</value>
<value>BOB</value>
</set>
</property>
<property name="wife" >
<null></null>
</property>
<property name="info">
<props>
<prop key="学号" >211134028</prop>
</props>
</property>
</bean>
拓展方式注入(P)
需要导入XML约束
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.wzs.pojo.user" p:age="18" p:name="韦智深"/>
</beans>
getBean的参数问题
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
user user1 = (user) context.getBean("user");
System.out.println(user1.toString());
}
}
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
user user1 = context.getBean("user", user.class);
System.out.println(user1.toString());
}
}
拓展方式注入(C)
有参构造器注入
<bean id="user" class="com.wzs.pojo.user" c:age="18"/>
bean的作用域
创建 bean 定义时,将创建一个配方来创建该 bean 定义所定义的类的实际实例。 bean 定义是配方的想法很重要,因为它意味着与类一样,您可以从一个配方中创建许多对象实例。
您不仅可以控制要插入到从特定 bean 定义创建的对象中的各种依赖项和配置值,还可以控制从特定 bean 定义创建的对象的范围。这种方法功能强大且灵活,因为您可以选择通过配置创建的对象的范围,而不必在 Java 类级别上烘烤对象的范围。可以将 Bean 定义为部署在多个范围之一中。 Spring 框架支持六个范围,其中只有在使用网络感知ApplicationContext时才可用。您也可以创建自定义范围。
如果使用默认的singleton,如果使用同一个id进行实例化对象时,多个对象的地址相同。
bean的自动装配
自动装配是Spring满足bean依赖一种方式!
Spring会在上下文中自动寻找,并自动给bean装配属性!
Spring三种装配的方式
- xml中显示的配置
- 在java中显示配置
- 隐式的自动装配
<!--byName:会在容器的上下文寻找,和自己对象的set方法后边对应的bean id-->
<bean id="person" class="com.wzs.pojo.person" autowire="byName">
<property name="name" value="wzs"/>
</bean>
满足后可自动装配。取代ref
<!--byType:会在容器上下文中查找,和自己对象属性类型相同的bean -->
<bean id="person" class="com.wzs.pojo.person" autowire="byType">
<property name="name" value="wzs"/>
</bean>
buName:保证bean的 id唯一,并且这个bean需要和自动注入的属性的set方法的值一致。
byType:保证bean的class唯一,并且这个bean需要和自动注入的属性的类型一致。
bean的生命周期
spring注解开发
使用注解的须知:导入约束
配置注解的支持
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired
:::info
如果出现NoSuchBeanDefinitionException错误,应首先检查是否出现值需要扫描的对象是否为组件,即是否加入了注解。
:::
public class person {
@Autowired
private Cat cat;
@Autowired
private Dog dog;
}
@Autowired(required=false),假如已经定义好的Bean中找不到对应的类型,允许不注入,这样就没有了异常抛出。
- 如果找到多个相同类型的组件,再根据属性的名称作为组件id去spring容器中找:annotationContext.getBean(“person”) 。
- required:属性默认为true,表示自动注入的Bean必须能够找到,否则就会报null,设置为false,可以在Spring容器自动注入Bean找不到的话,返回null,不会报错。
- @Autowired可以和@Qualifie注解使用,用来指定注入的组件id,而不是使用属性名。
- @Autowired默认先按Type进行匹配,如果找到多个bean,则又会按照组件id方式进行匹配(需要@Qualifier(“name”)配合)。查找XML中的多个对象,默认使用第一个。制定一个装配的值。
@Resource
@Resource 注解和@Autowired注解作用比较相似,也是实现组件的自动注入。它是JAVA2EE提供的注解,使用的时候需要导入javax.annotation.Resourc 。
当没有id匹配,class都相同时,Resource就无法找到
@Resource默认按照组件id自动注入,如果按照默认组件id找不到bean时,再按照类型去匹配。
注入顺序
- 同时指定了组件id和type,则从Spring上下文中找到唯一匹配的bean进行注入,找不到则抛出异常。
- 指定了组件id,则从上下文中查找名称(id)匹配的bean进行注入,找不到则抛出异常。
- 指定了type,则从上下文中找到类型匹配的唯一bean进行注入,如果找不到或者找到多个,都会抛出异常。
- 既没有指定组件ide,又没有指定type,则自动按照组件id方式进行注入;找不到的话,则回退为一个原始类型进行匹配,如果匹配则自动注入。
@Autowired 和 @Resource区别
@Autowired属于Spring注解,@Resource 由JAVA2EE提供,需要导入包javax.annotation.Resource。
@Autowired默认按Type注入,组件id的方式需要与@Qualifier(“name”)配合使用;
@Resource同时支持Type和组件id方式注入,默认按组件id注入。
@Autowired只包含一个参数:required,标明是否开启自动注入,默认是true。
而@Resource包含七个参数,最重要的两个参数是:name 和 type,用来指定注入的方式。
@Autowired可以作用在:构造器、方法、参数、成员变量和注解上,
@Resource可以作用在:类、成员变量和方法上。
使用注解开发
AOP的包必须导入包,引入context约束
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.wzs.pojo"/>
<context:annotation-config/>
</beans>
@Compoent
value注解代表这个类在Spring中的id,这相当于XML方式定义的Bean的id,也可以简写成,@Compoent(“role”),甚至直接写成@Component,不写的话IOC容器默认类名,但是以首字母小写的形式作为id,为其生成对象装配到容器中。
//等价于在bean里注册了
@Component
public class User {
public String name="wzs";
}
等价于
<bean id="user" class="com.wzs.pojo.user"/>
@Value
@Component
public class User {
@Value("weizhishen")//等价于<property name="name" value="weizhishen"/>
public String name;
}
@Compoent衍生注解
dao【Repository】
service【Service】
controller【Controller】
都是代表将某个类注册到Spring容器中装配bean。
扫描组件
●context:include-filter子节点表示要包含的目标类
注意:通常需要与use-default-filters属性配合使用才能够达到“仅包含某些组件”这样的效果。即:通过将use-default-filters属性设置为false,禁用默认过滤器(这样就不会默认扫描包下全部类),然后扫描的就只是include-filter中的规则指定的组件了。
●context:exclude-filter子节点表示要排除在外的目标类,不需要禁用默认过滤器
名称皆为全类名。
<context:component-scan base-package="com.wzs.controller">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<context:component-scan base-package="com.wzs.controller">
<context:exclude-filter type="assignable" expression="com.wzs.controller.UserController"/>
</context:component-scan>
一般用于spirng整合mybatis。
<context:component-scan base-package="com.wzs.controller">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
表示默认扫描所有包,即controller,mapper,service等等,默认为true,一般在spring.xml里面与exclude-filter搭配使用,达到不注入controller的效果(一般在springMVC.xml里配置扫描controller,在这里排除以避免重复扫描)。
:::info
在使用 use-default-filters 属性时要分清楚需要扫描哪些包,是不是需要使用默认的 Filter 进行扫描。
简单总结就是 use-default-filters=“false” 需要和 context:include-filter 一起使用,而不能和 context:exclude-filter 属性一起使用。
:::
注解加扫描配置的id
:::info
默认为类的小驼峰,即类名的首字母为小写的结果。
:::
@Controller("controller")
public class UserController {
}
AOP
:::info
Proxy使用的是反射包内的new方法。
参数:
ClassLoader loader:类加载器,指定加载动态生成的代理类的类加载器。
class[] interfaces:获取目标对象实现的所有接口的class对象的数组。
InvocationHandler h:设置代理类中的抽象方法如何重写
:::
非核心业务是横切关注点,即日志功能等,非核心业务
名词
:::info
- 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 …
- 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
- 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
- 目标(Target):被通知对象。
- 代理(Proxy):向目标对象应用通知之后创建的对象。
- 切入点(PointCut):切面通知 执行的 “地点”的定义。
- 连接点(JointPoint):与切入点匹配的执行点。
:::
动态代理:JDK原生的实现方式,需要被代理的目标类必须是衔接口。因为这个技术要求代理对象和目标对象实现同样的结构。
cglib:通过继承被代理的目标类实现代理,所以不需要目标类实现接口。
AspectJ:本质上是静态代理,将代理逻辑“织入”被代理的目标类变异的到的字节码文件。所以最终的效果是动态的。weaver就是织入器。Spring只是借用了AspectJ中的注解。
:::info
AOP:切面类和目标类都需要交给IOC容器管理
切面类必须通过@Aspect注解标识为一个切面
在Spring的配置文件中设置<aop:aspectj-autoproxy />开启基于注解的AOP
:::