spring
Bean的作用范围
通过配置scope属性
属性取值: singleton 单例(默认值)
Prototype 多例
Request 作用范围为一次请求,和当前请求的转发
Session 作用范围为一次会话
Globalsession 作用范围是一次全局会话
Bean的生命周期:
涉及两个属性:
init-method
destroy-method
单例:
出生:容器创建 对象出生
活着:只要容器在,对象就一直存在
死亡:容器销毁
多例:
出生:每次使用时创建对象
活着:只要对象在使用中
死亡:当对象长时间不使用并且没有被引用则会被GC销毁
Spring的依赖注入:
注入的方式有三种:
使用构造函数注入
使用set方法注入
使用注解注入
注入的数据类型有三类:
基本数据类型和String
其他bean类型(必须是在spring的配置文件中出现过的bean)
复杂类型(list set map array)
使用构造函数注入: 标签:constructor-arg
属性:
type:指定参数的类型
index 指定参数的类型
name 指定参数的名称
value指定基本数据类型或string
ref指定其他bean类型数据
使用set方法注入 标签property:
属性name value
用于创建bean对象
使用注解注入:
[^ ]: 使用这些注解的前提配置<context:component-scan base-package=”com.syl”/>
@
作用:就相当于配置了一个bean标签。
它能出现的位置:类上面
属性: value.含义是指定bean的id。当不写时,它有默认值,默认值是:当前类的短名首字母改小写。
由此注解衍生的三个注解:
@Controller 一般用于表现的注解
@service 一般用于业务层
@Repository 一般用于持久层
他们和@Component的作用及属性都是一模一样
用于注入数据的
- @Autowired
作用:自动按照类型注入。只要有唯一的类型匹配就能注入成功。如果注入的bean在容器中类型不唯一时,它会把变量名称作为 bean的id,在容器中查找,找到后也能注入成功。如果没有找到一致的bean的id,则报错。当我们使用注解注入时,set方法就不是必须的了。- @Qualifier
作用:在自动按照类型注入的基础之上(Autowired基础上),再按照bean的id注入。它在给类成员注入数据时,不能独立使用。但是再给方法的形参注入数据时,可以独立使用。
属性: value:用于指定bean的id
1 |
|
@Resource 相当于上面两个的结合
作用:直接按照bean的id注入。
属性:
name:用于指定bean的id.
1 |
|
@Value:
作用:用于注入基本类型和String类型数据。它可以借助spring的EL表达式读取 properties文件中的配置。
属性: value:用于指定要注入的数据
用于改变作用范围的
@Scope
作用:用于改变bean的作用范围
属性:
value:用于指定范围的取值。singleton | prototype | request | session | globalsession
创建spring工具类的来代替XML文件
1 | //将当前类作为spring配置类和XML文件放在同一包下可以使用字节码文件快速定位xml配置文件 |
获取对象之前读取配置文件的时候将
1 | ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); |
替换为
1 | ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration. Class); |
@PropertySource(“classpath:*.properties”)
作用:将properties文件加载进spring
使用的时候使用spring的EL表达式(spring4.3之后生效)
@value(“${properties文件中的属性名}”)来获取数据
动态代理
作用:
不改变源码的基础上,对已有方法增强。(它是AOP思想的实现技术》
分类:基于接口的动态代理:
要求:被代理类最少实现一个接口
提供者: JDK官方
涉及的类: Proxy
创建代理对象的方法: newProxyInstance(ClassLoader ,Class[], Invocat ionHandler)
1 | /*参数的含义: |
基于子类的动态代理:
要求:被代理类不能是最终类.不能被final修饰
提供者:第三方CGLib
涉及的类: Enhancer
创建代理对象的方法: create(Class,Callback);静态方法
参数的含义:
Class:被代理对象的字节码
Callback:如何代理。它和Invocat ionHandler的作用是一样的。 它也是一个接口, 我们一般使用该接口的子接口MethodInterceptor
在使用时我们也是创建该接口的匿名内部类。
1 |
|
切入点表达式:
关键字: execution(表达式)
表达式写法:
访问修饰符返回值包名.包名.. .类名.方法名(参数列表)
全匹配方式:
public void com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
访问修饰符可以省略
void com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
返回值可以使用通配符,表示任意返回值。通配符是*
* com.itheima.service.impl.CustomerServiceImpl.saveCustomer()
包名可以使用通配符,表示任意包。但是,有几个包就需要写几个*
*.*.*.*.CustomerServiceImpl.saveCustomer()
包名可以使用..表示当前包及其子包
* com. .CustomerServiceImpl. saveCustomer()
类名和方法名都可以使用通配符
* com..*.*()
参数列表可以使用具体类型,来表示参数类型
基本类型直接写类型名称: int
引用类型必须是包名.类名。java. lang. Integer
参数列表可以使用通配符,表示任意参数类型,但是必须有参数
* com..*.*(*)
参数列表可以使用。.表示有无参数均可,有参数可以是任意类型
* com..*.*(..)
全通配方式:
* *..*.*(..)
实际开发中,我们一般情况下,我们都是对业务层方法进行增强:
所以写法:com.syl.service.impl.*.*(..)
定义通用的切入点表达式:如果是写在了aop:aspect标签内部,则表示只有当前切面可用
<aop:pointcut expression="execution(com..*.*(..))”id="pt1"/>
如果写在aop:aspect标签外部则必须写在其上面
环绕通知
问题:
当我们配置了环绕通知之后,切入点方法没有执行,而环绕通知里的代码执行了。
分析:
由动态代理可知,环绕通知指的是invoke方法,并且里面有明确的切入点方法调用。而我们现在的环绕通知没有明确切入点方法调用。
解决:
spring为我们提供了一一个接口: ProceedingJoinPoint。该接口可以作为环绕通知的方法参数来使用。
在程序运行时,spring框架会为我们提供该接口的实现类,供我们使用。
该接口中有一个方法,proceed(), 它的作用就等同于method . invoke方法,就是明确调用业务层核心方法(切入点方法)
1 | public object aroundPrintLog(ProceedingJoinPoint pjp){ |
注解:
@Aspect //类名上
空函数用来定义切点
@Pointcut(“execution(* com.syl.serviceImpl..(..))”)
public void pc() {}
@Before(“pc()”)
@AfterReturning(“pc()”)
@AfterThrowing(“pc()”)
@After(“pc()”)
@Around(“pc()”)
如果使用注解,方法执行顺序会有变动,最终通知先于后置通知执行,这时建议使用环绕
声明式事务
1 | <!--第一步:配置事务管理器 --> |
^注: Aop(aop:config)关联事务通知(tx:advice),事务通知关联事务管理器
1 | <!--spring基于XML和注解组合的配置步骤--> |
在需要事务的地方使用
@Transactional注解
该注解可以写在接口上,类上和方法上。
写在接口上,表示该接口的所有实现类都有事务。
写在类上,表示该类中所有方法都有事务。
写在方法,表示该方法有事务。
优先级:就近原则。
@Transactional(propagation = Propagation.SUPPORTS, readonly = true)