- 控制反转(IOC) 切面编程(AOP)
资源管理
Resource
Spring 通过Resource接口访问底层资源
Resource可以管理各种资源
ResourceLoader
- 资源加载接口
- spring中所有的ApplicationContext都实现了这个接口 因此在Spring环境下可以随时加载资源
IOC
控制反转
当IoC容器创建Bean对象之后,把他注入业务系统,同时建立Bean对象之间的依赖关系。
通过配置信息的变化实现程序的多态
使得程序不再具有主动性而变为被动接收对象
降低耦合,专注业务
ApplicationContext
- 接口 org.springframework.context.ApplicationContext 代表了IoC容器,他同时负责配置,实例化,装配Bean
- ApplicationContext 时BeanFactory的子接口, ApplicationContext 集成了AOP,管理消息资源,发布事件,在应用层注入上线文等功能
- 一旦创建了ApplicationContext接口的实现类对象,就创建了IoC容器。 在创建IoC容器时要将Spring配置文件传送给IoC容器的构造函数
//使用ClassPathXmlApplicationContext创建IoC容器
//需要从多个配置文件生成IoC容器只需要添加参数即可
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
- 标签可以组合配置文件
从容器中读取Bean对象
- 根据类型找到Bean对象
stuDo etstu = context.getBean(stuDo.class);
- 根据名字找到Bean对象
student getStu = (student) context.getBean("getStu");
public class HelloBiz {
public String sayHello(String name){
return "hello: Mr." + name;
}
}
<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hello" class="HelloBiz"/>
</beans>
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
HelloBiz helloBiz = (HelloBiz) context.getBean("hello");
System.out.println(helloBiz.sayHello("jack"));
}
打印结果:hello: Mr.jack
Bean
bean就是一个对象 一个bean标签相当于new了一个bean对象
id = 变量名
通过下标赋值<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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="user" class="com.hou.pojo.User">
<constructor-arg index="0" value="hou"/>
</bean>
</beans>
对象赋值
<bean id="user" class="com.hou.pojo.User">
<constructor-arg type="java.lang.String" value="dong"/>
</bean>
参数名赋值
<bean id="user" class="com.hou.pojo.User">
<constructor-arg name="name" value="hou"></constructor-arg>
</bean>
- 获取spring相应配置中Spring实例化的对象
参数String 为配置文件名
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
由上通过context可以得到Bean 实例
//context.getBean();返回的是一个Object对象,需要指定对象强制转换
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
(该对象是由Spring创建的)
- 必须要有set方法进行依赖注入
Spring配置
别名
alias
<alias name="hello" alias="newhello"/>
Bean配置
id Bean的唯一标识符
class Bean的全限命名 包名 + 类型
name 也是别名,name更高级,可以同时取多个别名
<bean id="hello" class="pojo.Hello" name="hello2,u2 u3"/>
import
- 一般用于团队开发使用,它可以将多个配置文件导入合为一个
依赖注入流程
1. ApplicationContext 的创建和初始化依赖于配置信息,这些配置信息可以来自于**xml、Java代码、注解**
2. 每个Bean 的依赖以属性、构造函数参数或静态工厂方法参数的形式出现。当实际创建这些Bean 时,这些依赖也将提供给该Bean。
3. 每个属性或构造函数的参数既可以是一个实际值,也可以是对该容器中另一个Bean的引用。
4. 每个指定属性或构造函数参数的值必须能够转化成特定格式或构造参数所需类型。默认情况下Spring可以把String 转换成其他各种内置类型,如 int, long,boolean ...
DI依赖注入
- 各种类型的注入
<bean id="hello" class="pojo.Hello">
<property name="str" value="stttt"/>
</bean>
<bean id="user" class="pojo.User">
<!--普通注入-->
<property name="name" value="qzw"/>
<!--list-->
<property name="hobby">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<!--boolean-->
<property name="boy">
<null/>
</property>
<!--map-->
<property name="maps">
<map>
<entry key="1" value="1"/>
<entry key="2" value="2"/>
<entry key="3" value="3"/>
</map>
</property>
<!--Bean-->
<property name="hel" ref="hello"/>
</bean>
Bean作用域
- 下三个只能在Web环境下使用,否则会爆出异常
配置Bean的作用域
- 在Bean配置文件中配置Bean的作用域
<bean id="hello" class="pojo.Hello" scope="singleton"/>
- 使用注解声明作用域
@Component("hello")
@Scope("singleton")
public class Hello {
...
}
singleton 与 prototype
- singleton 单例 Spring的单例存储在缓存中而不是JVM, 创建之后所有对该命名的Bean的引用返回的都是缓存里面的对象
- prototype 与singleton 相反 每一个对该命名的Bean 都是一个新的对象实例
set方法注入
<bean id="userDao1" class="com.qzw.dao.UserDao"></bean>
<bean id="userBiz" class="com.qzw.bean.UserBiz">
<property name="userDao" ref="userDao1"/>
</bean>
- 如上加入
<property>
标签来指定对应的set方法 <property>
参数name与set方法的名字相对应<property>
参数ref 指定配了的实例id
注解注入
注解支持
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
</beans>
@Autowired
- 注入模式 | no | 默认模式,没有自动装配,对于Bean之间的引用必须定义ref | | —- | —- | | byName | 通过属性名进行自动适配,Spring 按照属性名查找所有的Bean的定义 | | byType | 通过属性类型进行自动适配,如果容器中存在一个与指定类型相同的Bean那么将于该属性自动适配,否则抛出异常 | | constructor | 类似于byType,但是应用于构造函数参数。如果容器中没有找到与构造函数参数一致的Bean,那么将会抛出异常 |
自动注入
直接在属性上使用即可,也可以在set方法上面使用
使用了Autowried之后可以不用写set方法
@Nullable标记了某个字段,说明该字段可以为null
//如果显示定义了@Autowired的required属性为false,说明这个对象可以为null 否则不允许为null
@Autowired(required = false)
private Cat cat;
//说明了cat对象是可以为null的
联合@Qualifier(value=“***”)可以指定唯一bean对象注入
**[@Resource ](/Resource ) ** 与@Autowired有异曲同工之出
@Componet 组件
Autowire注入的解释
在组件注册了之后,组件会加入到IoC容器之中,组件名唯一,当在使用Autowire注入时IoC容器会扫描组件然后根据表格里面的注入模式进行注入 ,, **需要注意的是,Compoent组件并不唯一,Service(服务层组件注解)、Reqository(持久层注解)都是组件**
@Componet衍生注解
1. dao 【@Repository】
2. service 【@Service】
3. controller 【@Controller】
这四个功能都是一样的,都是代表将某个类注册道Spring中
@Scope(“”) 作用域详细参数如上:Bean作用域
@Name 与 @ManagedBean
- 使用Named 或 ManagedBean 可以代替@Component
- 这样的注解会让每一层的形式都相同,不利于区别
@Bean and @Configuration
- @Bean 注解把方法返回的对象当成Bean处理
- @Configuration 声明Bean
@Primary
- 当遇到同一类型中存在多个对象的情况,,使用Primary提示优先注入对象
@Qualifier
标记依赖对象
使用Java的方式配置Spring
package user;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class stuDo {
@Bean
public student getStu(){
return new student();
}
}
package user;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class student {
private String name;
public student() {
}
public String getName() {
return name;
}
@Value("qinzw")
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "student{" +
"name='" + name + '\'' +
'}';
}
}
ApplicationContext context = new AnnotationConfigApplicationContext(stuDo.class);
student getStu = (student) context.getBean("getStu");
System.out.println(getStu.toString());
@Configuration
//这个注解也是Spring容器托管注册道容器中,应为他本来就是一个@controller @Configuration代表这是一个配置类就和我们之前看的beans.xml
通过单例封装IoC容器
从性能考虑多容器模式完全是浪费,因此把IoC 封装成单例模式
public class BeanFactory {
private static ApplicationContext context;
static{
context = new ClassPathXmlApplicationContext("beans.xml");
}
public static Object getBean(String beanName){
return context.getBean(beanName);
}
}
P命名空间
p:namespace
- 使用p:属性名,可以直接给Bean的属性赋值。这种赋值方式的效果等同于
<property>
- schema必须要支持P命名空间
- 使用p:属性名,可以直接给Bean的属性赋值。这种赋值方式的效果等同于
C命名空间
- 类似于p:namespace c:namesapce 可以简化构造函数的配置
- c: namespace 的炒作是为了简化构造函数的注入操作,为了使用c: namespace代替构造函数需要引入xmlns:c 的schame。
- 例如 c: “属性名”-ref=“” 的格式
depends-on属性
- 当两个Bean之间的依赖关系没有明确指定,使用 depends-on属性,可以明确告诉IoC 容器, 在某个Bean的初始化之前,必须要先初始化它的依赖的Bean 对象
Aware接口
Spring提供了很多Aware接口,用于向Bean对象提供IoC容器下的基础环境依赖。
- Bean 实现了ApplicationContextAware接口即可在Bean运行时查看IoC容器的环境信息
BeanFactory
- BeanFactory 接口时Spring 组件的注册中心和配置中心
- BeanFactory 接口的实现需要管理大量Bean的定义, 每个 Bean 定义了唯一的ID
- BeanFactory是访问Spring 容器的跟接口
- 如果Bean是单例模式,则直返回Bean对象的引用,对于其他类型的作用域,查找实际上是Bean对象实例化的过程
AOP
- 面向切面编程
代理模式
- SpringAOP的底层
分类
- 静态代理
- 动态代理
静态代理
角色分析
- 抽象角色
- 真实角色
- 代理角色:代理真实角色,代理真实角色后通常做一些附属操作
- 客户:访问代理对象的人
不用改变原来的代码增加其他功能
动态代理
- 动态代理与静态代理角色是一样的
- 动态代理的代理类是动态生成的,不是我们直接写好的
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口:JDK动态代理
- 基于类:cglib
- Java字节码实现:javasist
两个类:
- Proxy : 提供了动态代理类和实例的static方法, 它也是创建所有动态代理类的超类
public class Proxy implements java.io.Serializable {
...
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException{
...
}
//返回的是动态代理对象
}
InvocationHandler : 提供invoke的方法实现处理实例,返回结果
动态代理的本质,就是反射机制的实现
一个动态代理类代理的是一个接口,代理的是一类业务
一个动态代理类可以代理多个类,只要他们实现了共同的接口
AOP在Spring中的作用
提供声明式事务,允许用户自定义切面
配置
- 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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-context.xsd">
<aop:aspectj-autoproxy/>
</beans>
- java 配置模式
@Configuration
@EnableAspectJAutoProxy
public class Hello {
...
}
声明切面
切面中包含切入点、通知、引入等信息,因此一个系统中可以定义多个切面,每个切面的内容相互独立
:
新建一个Bean
@Component
public class DbProxy{
}
@Aspect声明切面
@Component
@Aspect
public class DbProxy{
}