Spring5
内容
-
IOC容器
-
什么是IOC
-
IOC底层原理
-
IOC接口(beanFactory)
-
IOC操作Bean管理(基于xml)
-
IOC操作Bean管理(基于注解)
-
-
AOP
IOC
-
什么是Ioc
控制反转,把对象的创建和对象之间的关系交给spring进行管理
目的:解耦,是耦合度降低 -
Ioc底层原理
xml解析、工厂模式、反射
-
BeanFactory
接口-
IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
-
Spring 提供ioc容器的两种方式:(两个接口)
-
BeanFactory
:IOC容器的基本实现,是spring内部使用的接口,不提供给开发人员使用 加载配置文件的时候不会创建对象,在使用对象的时候会创建。 -
ApplicationContext
BeanFactory接口的子接口,提供更强大的功能,一般由开发人员使用,加载配置文件的时候就会创建对象。 -
ApplicationContext
有实现类CalssPathXmlApplicationContext
- FileSystemXmlApplicationContext
-
-
选中接口 +F4
出现该接口的层级结构
hierarchy
ˈhaɪərɑːki’ 等级层级
ClassPathXmlApplicationContext和FileSystemXmlApplicationContext的区别
classpath:前缀是不需要的,默认就是指项目 src
目录下的配置文件
ApplicationContext factory = new ClassPathXmlApplicationContext("classpath:appcontext.xml");
ApplicationContext factory = new ClassPathXmlApplicationContext("appcontext.xml");
FileSystem: 即系统文件路径,文件的目录
1.没有盘符的是项目工作路径,即项目的根目录;
2.有盘符表示的是文件绝对路径.
ApplicationContext factory = new FileSystemXmlApplicationContext("classpath:appcontext.xml");
ApplicationContext factory = new FileSystemXmlApplicationContext("file:F:/workspace/example/src/appcontext.xml");
**Bean管理是指两个操作 **
- Bean的创建
- bean的注入
bean管理的两种方式
- 基于xml配置
- 基于注解
-
IOC操作bean管理(基于xml配置)
-
基于xml配置方式
<--配置User对象创建--> <bean id="user" class="com.atguigu.spring5.User"></bean>
- 在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象创建
- 在 bean 标签有很多属性,介绍常用的属性
- id 属性:唯一标识
- class 属性:类全路径(包类路径)
-
基础xml方式注入属性
-
DI 依赖注入(set注入、构造器注入等)
<!--属性值包含特殊符号 1 把<>进行转义 < > 2 把带特殊符号内容写到CDATA --> <![CDATA[<=WEWR]]> <property name="address"> <value><![CDATA[<<南京>>]]></value> </property>
-
-
Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
-
普通 bean:在配置文件中定义 bean 类型就是返回类型
-
工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样
-
第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
-
第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
public class MyBean implements FactoryBean<Course> { //定义返回bean @Override public Course getObject() throws Exception { Course course = new Course(); course.setCname("abc"); return course; } @Override public Class<?> getObjectType() { return null; } @Override public boolean isSingleton() { return false; } }
<bean id="myBean" class="com.atguigu.spring5.factorybean.MyBean"> </bean> @Test public void test3() { ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml"); Course course = context.getBean("myBean", Course.class); System.out.println(course); }
-
-
-
IOC操作Bean管理(Bean的作用域)
- 在spring中,设置bean的创建是单实例还是多实例
- 在spring中,默认情况下,bean是单例的
- 如何设置是单实例还是多实例
- 在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
- scope 属性值
- 第一个值 默认值,singleton,表示是单实例对象
- 第二个值 prototype,表示是多实例对象
- singleton和prototype区别
- singleton是单实例,prototype是多实例
- 设置scope为single时,加载spring配置文件时就会创建单实例对象,
设置scope为prototype时,不是在加载 spring 配置文件时候创建对象,在调用getbean 方法的时候创建多实例对象
-
IOC操作bean管理(bean的生命周期)
-
生命周期 :从对象的创建到对象的销毁的过程
-
bean的生命周期:
- 通过构造器创建bean实例(无参构造器)
- 为bean的属性设置值和对其它bean的引用(调用set方法)
- 调用bean的初始化方法(需要进行配置初始化的方法)
- bean使用(对象获取到了)
- 当容器关闭时,调用bean的销毁方法(需要配置销毁方法)
-
演示bean的生命周期
<bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod"> <property name="oname" value="手机"></property> </bean>
public class Orders { //无参数构造 public Orders() { System.out.println("第一步 执行无参数构造创建bean实例"); } private String oname; public void setOname(String oname) { this.oname = oname; System.out.println("第二步 调用set方法设置属性值"); } //创建执行的初始化的方法 public void initMethod() { System.out.println("第三步 执行初始化的方法"); } //创建执行的销毁的方法 public void destroyMethod() { System.out.println("第五步 执行销毁的方法"); } }
@Test public void testBean4() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml"); Orders orders = context.getBean("orders", Orders.class); System.out.println("第四步 获取创建bean实例对象"); System.out.println(orders);= //手动让bean实例销毁 context.close(); }
-
baen的后置处理器,bean的生命周期有七步
- 通过构造器创建bean的实例(无参构造器)
- 为bean的属性设置值和对其它bean的引用(调用set方法)
- 把bean实例传递bean后置处理器的方法
postProcessBeforeInitialization
- 调用bean的初始化方法(需要配置初始化方法)
- 把bean实例传递bean后置处理器的方法
postProcessAfterInitialization
- bean可以使用了(bean对象获取到了)
- 当容器关闭的时候,调用bean的销毁方法(需要配置销毁的方法)
-
配置后置处理器
<bean id="orders" class="com.atguigu.spring5.bean.Orders" init-method="initMethod" destroy-method="destroyMethod"> <property name="oname" value="手机"></property> </bean> <!--配置后置处理器--> <bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>
创建类,实现接口BeanPostProcessor,创建后置处理器 public class MyBeanPost implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("在初始化之前执行的方法"); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("在初始化之后执行的方法"); return bean; } }
@Test public void testBean3() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml"); Orders orders = context.getBean("orders", Orders.class); System.out.println("第四步 获取创建bean实例对象"); System.out.println(orders); //手动让bean实例销毁 context.close(); }
-
-
后置处理器在xml配置后加载后就生效了
-
iOC操作bean管理(xml自动装配)
-
什么是自动装配
-
根据指定装配规则(根据属性名称或者属性类型),Spring自动匹配属性进行注入
-
演示自动装配
public class Emp { private Dept dept; public void setDept(Dept dept) { this.dept = dept; } @Override public String toString() { return "Emp{" + "dept=" + dept + '}'; } public void test() { System.out.println(dept); } }
<!--实现自动装配 bean标签属性autowire,配置自动装配 autowire属性常用两个值: byName根据属性名称注入 ,注入值bean的id值和类属性名称一样 byType根据属性类型注入 --> <bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byType"> <!--<property name="dept" ref="dept"></property>--> </bean> <bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
-
-
ioc操作bean管理(引入外部配置文件)
-
创建外部配置文件,properties 格式文件,写数据库信息
-
把外部 properties 属性文件引入到 spring 配置文件中
引入 context 名称空间context:property-placeholder
placeholder 占位符[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0g3wjbMp-1654580557505)(C:\Users\StarLee\AppData\Roaming\Typora\typora-user-images\image-20220519224943348.png)]
-
-
-
IOC操作bean管理(注解方式)
-
什么是注解
- 注解是代码特殊标记,格式 :@注解名称(属性名称=属性值,属性名称=属性值…)
- 使用注解 注解作用于类上面,属性上面,方法上面
- 使用注解的目的:简化xml配置
-
Spring针对bean管理中创建对象提供的注解
- @Component
- @Controller
- @Service
- @Repository
-
基于注解方式的对象创建
-
引入依赖
-
开启组件扫描
<!--开启组件扫描 1 如果扫描多个包,多个包使用逗号隔开 2 扫描包上层目录 --> <context:component-scan base-package="com.atguigu"></context:component-scan>
-
创建类在类上面添加注解
//在注解里面 value 属性值可以省略不写, //默认值是类名称,首字母小写 //UserService -- userService @Component(value = "userService") //<bean id="userService" class=".."/> public class UserService { public void add() { System.out.println("service add......."); } }
-
-
基于注解方式实现属性注入
-
@Autowired:根据属性类型进行自动装配
//定义 dao 类型属性 //不需要添加 set 方法 //添加注入属性注解 @Autowired private UserDao userDao;
-
@Qualifier:根据名称进行注入
这个@Qualifier 注解的使用,和上面@Autowired 一起使用//定义 dao 类型属性 //不需要添加 set 方法 //添加注入属性注解 @Autowired //根据类型进行注入 @Qualifier(value = "userDaoImpl1") //根据名称进行注入 private UserDao userDao;
-
@Resource:可以根据类型注入,可以根据名称注入
//@Resource //根据类型进行注入 @Resource(name = "userDaoImpl1") //根据名称进行注入 private UserDao userDao;
-
@Value:注入基本类型属性
@Value(value = "abc") private String name;
-
-
完全注解开发
-
创建配置类替代xml配置文件
@Configuration //作为配置类,替代 xml 配置文件 @ComponentScan(basePackages = {"com.atguigu"}) //代替<context:component-scan > public class SpringConfig { }
-
测试代码
AnnotationConfigApplicationContext
package com.atguigu; @Service public class UserService { @Value(value = "abc") private String name; }
@Test public void testService2() { //加载配置类 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = context.getBean("userService", UserService.class); System.out.println(userService); }
-
-
AOP
什么是Aop
- 面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护。
AOP底层原理
-
AOP底层是动态代理(jdk动态代理,cglib动态代理)
-
有接口的情况,使用jdk动态代理
- 创建接口的实现类代理对象,增强类的方法
-
没有接口的情况,使用cglib动态代理
- 创建该类的子类的代理对象,增强类的方法
-
-
AOP(JDK动态代理)
-
使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象
-
调用newProxyInstance方法
-
方法三个参数
- 第一参数,类加载器
- 第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
- 第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分
-
编写JDK动态代理代码
-
创建接口定义方法
public interface UserDao { public int add(int a,int b); public String update(String id); }
-
创建接口实现类,实现方法
public class UserDaoImpl implements UserDao { @Override public int add(int a, int b) { return a+b; } @Override public String update(String id) { return id; } }
-
使用 Proxy 类创建接口代理对象
public class JDKProxy { public static void main(String[] args) { //创建接口实现类代理对象 Class[] interfaces = {UserDao.class}; // Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new InvocationHandler() { // @Override // public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // return null; // } // }); UserDaoImpl userDao = new UserDaoImpl(); UserDao dao = (UserDao)Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = dao.add(1, 2); System.out.println("result:"+result); } } //创建代理对象代码 class UserDaoProxy implements InvocationHandler { //1 把创建的是谁的代理对象,把谁传递过来 //有参数构造传递 private Object obj; public UserDaoProxy(Object obj) { this.obj = obj; } //增强的逻辑 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法之前 System.out.println("方法之前执行...."+method.getName()+" :传递的参数..."+ Arrays.toString(args)); //被增强的方法执行 Object res = method.invoke(obj, args); //方法之后 System.out.println("方法之后执行...."+obj); return res; } }
-
-
-
AOP(术语)
- 连接点
类里面的那些方法可以被增强,这些方法都叫做链接点 - 切入点
类中真正被增强的方法 - 通知(增强)
实际增强的逻辑称为通知- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知
- 切面
是动作,把通知织如切入点的过程(自己把增强的类称为切面)
- 连接点
-
AOP操作
-
Spring 框架一般都是基于 AspectJ 实现 AOP 操作,AspectJ 不是 Spring 组成部分,独立 AOP 框架
-
基于 AspectJ 实现 AOP 操作
- 基于 xml 配置文件实现
- 基于注解方式实现使用
-
切入点表达式
- 切入点表达式作用:知道对哪个类里面的哪个方法进行增强
- 语法结构: execution([权限修饰符] [返回类型] [类全路径] 【方法名称】([参数列表]) )
- 访问权限修饰符可以为 * 表示所有
- 返回类型可以为空
- 方法名称可以为 * 表示所有
- 参数列表可以 …
- 举例 1:对 com.atguigu.dao.BookDao 类里面的 add 进行增强
execution(* com.atguigu.dao.BookDao.add(…)) - 举例 2:对 com.atguigu.dao.BookDao 类里面的所有的方法进行增强
execution(* com.atguigu.dao.BookDao.* (…)) - 举例 3:对 com.atguigu.dao 包里面所有类,类里面所有方法进行增强
execution(* com.atguigu.dao.. (…))
-
代码
-
创建类,在类里面定义方法 cglib
-
public class User { public void add() { System.out.println("add......."); } }
-
-
创建增强类(编写增强逻辑)
在增强类里面,创建方法,让不同方法代表不同通知类型
-
/增强的类 public class UserProxy { public void before() {//前置通知 System.out.println("before......"); } }
-
-
进行通知的配置
-
开启注解扫描(两种方式xml,或者注解)
-
使用注解创建 User 和 UserProxy 对象
//被增强的类 @Conponent public class User{ //增强类 @Conponent public class UserProxy{}
-
在增强类上添加注解
@Aspect
生成代理对象@Component @Aspect //生成代理对象 public class UserProxy {
-
开启生成代理对象两种方式(xml,或者注解)
-
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
-
@EnableAspectJAutoProxy
-
-
-
配置不同类型通知
-
在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
@Component @Aspect //生成代理对象 public class UserProxy { //前置通知 //@Before 注解表示作为前置通知 @Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void before() { System.out.println("before........."); } //后置通知(返回通知) @AfterReturning(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void afterReturning() { System.out.println("afterReturning........."); } //最终通知 @After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void after() { System.out.println("after........."); } //异常通知 @AfterThrowing(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void afterThrowing() { System.out.println("afterThrowing........."); } //环绕通知 @Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("环绕之前........."); //被增强的方法执行 proceedingJoinPoint.proceed(); System.out.println("环绕之后........."); } }
-
相同切入点抽取 @Pointcut注解作用在方法上
@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") public void pointdemo() { } //前置通知 //@Before 注解表示作为前置通知 @Before(value = "pointdemo()") public void before() { System.out.println("before........."); }
-
完全注解开发,不使用xml文件
@Configuration @ComponentScan(basePackages = {"com.atguigu"}) @EnableAspectJAutoProxy(proxyTargetClass = true) public class ConfigAop { }
-
xml 开发
<!--创建对象--> <bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean> <bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean> <!--配置 aop 增强--> <aop:config> <!--切入点--> <aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/> <!--配置切面--> <aop:aspect ref="bookProxy"> <!--增强作用在具体的方法上--> <aop:before method="before" pointcut-ref="p"/> </aop:aspect> </aop:config>
-
-
-