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">
在其中配置bean
<bean id="accountdao" class="com.zhonghuan.Dao.impl.AccountDaoimpl"></bean>
</beans>
ApplicationContext的三个实现类
类创建的时机
ApplicationContext:在构建核心容器时,创建对象的策略的方式是立即创建的方式,读取完配置文件立即创建对象
BanFactory:创建对象的策略是延时加载,在通过id获取对象的时候才创建对象
Spring中的依赖注入
IOC的作用是降低程序间的耦合(依赖关系),依赖关系的管理都可以交给Spring,在当前类需要使用其它类的对象,由spring向我们提供,我们只需要在配置文件中说明,依赖关系的维护就称之为依赖注入
能注入的数据共三类
1.基本类型的数据和String
2.其他bean类型:在配置文件中或注释中配置过的bean
2.复杂类型和集合类型
基本数据类型:
java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。
byte,short,int,long,double,float,char,Boolean,
<!--把对象的创建交给spring来管理-->
<!--spring对bean的管理细节
1.创建bean的三种方式
2.bean对象的作用范围
3.bean对象的生命周期
-->
<!--创建Bean的三种方式 -->
<!-- 第一种方式:使用默认构造函数创建。
在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时。
采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
-->
<!-- 第二种方式: 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
<bean id="instanceFactory" class="com.itheima.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
-->
<!-- 第三种方式:使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)
<bean id="accountService" class="com.itheima.factory.StaticFactory" factory-method="getAccountService"></bean>
-->
<!-- bean的作用范围调整
bean标签的scope属性:
作用:用于指定bean的作用范围
取值: 常用的就是单例的和多例的
singleton:单例的(默认值)
prototype:多例的
request:作用于web应用的请求范围
session:作用于web应用的会话范围
global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl" scope="prototype"></bean>
-->
<!-- bean对象的生命周期
单例对象
出生:当容器创建时对象出生
活着:只要容器还在,对象一直活着
死亡:容器销毁,对象消亡
总结:单例对象的生命周期和容器相同
多例对象
出生:当我们使用对象时spring框架为我们创建
活着:对象只要是在使用过程中就一直活着。
死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收
-->
使用注解配置
使用注解和使用xml文件配置所用的xml文件约束不同
在使用注解之前,需要告知spring在创建容器时要扫描的包,
配置所需要的标签不是在beans的约束中,而是一个名称为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">
<!--告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是一个名称为
context名称空间和约束中-->
<context:component-scan base-package="com.itheima"></context:component-scan>
</beans>
根据作用类型注解分类
用于创建对象的:
1.@Component:
作用:把当前对象存储到容器中,
@Component(value = "accountservice")注解id默认值为类名首字母小写,
也可以通过value来更改,仅有一个value时可省略
下面三个注解与Component作用相同,是spring为了使三层架构更佳清晰
2.@Controller:用在表现层
3.@Service:用在业务逻辑层
4.@Repository:用在持久层
用于注入数据的
他们的作用就和在xml配置文件中的bean标签中写一个<property>标签的作用是一样的
1.Autowired:
作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
如果ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
如果Ioc容器中有多个类型匹配时:
出现位置:
可以是变量上,也可以是方法上
细节:
在使用注解注入时,set方法就不是必须的了。
2.Qualifier:
作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以(稍后我们讲)
属性:
value:用于指定注入bean的id。
3.Resource
作用:直接按照bean的id注入。它可以独立使用
属性:
name:用于指定bean的id。
以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
另外,集合类型的注入只能通过XML来实现。
Value
作用:用于注入基本类型和String类型的数据
属性:
value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
SpEL的写法:${表达式}
@Autowired
private AccountDao accountdao2;
权限修饰符 类名 对象名
当使用@AutoWrite注解按照类型自动注入时,首先会按照类名去map类型的Spring容器中寻找map中的value进行自动匹配,如果找到唯一匹配就自动注入,如果找到多个匹配结果就再将对象名与Spring Map容器的key进行匹配。
在使用注解将对象配置进Spring容器时,key为id,
value为public class AccountServiceimpl implements AccountService格式
用于注入数据的
他们的作用就和在xml配置文件中的bean标签中写一个 <property>标签的作用是一样的
Autowired:
作用:自动按照类型注入。只要容器中有唯一的一个bean 对象类型和要注入的变量类型匹配,就可以注入成功
如果ioc容器中没有任何bean的类型和要注入的变量类 型匹配,则报错。
如果Ioc容器中有多个类型匹配时:
出现位置:
可以是变量上,也可以是方法上
细节:
在使用注解注入时,set方法就不是必须的了。
Qualifier:
作用:在按照类中注入的基础之上再按照名称注入。它在给类成员注入时不能单独使用。但是在给方法参数注入时可以(稍后我们讲)
属性:
value:用于指定注入bean的id。
Resource
作用:直接按照bean的id注入。它可以独立使用
属性:
name:用于指定bean的id。
以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
另外,集合类型的注入只能通过XML来实现。
Value
作用:用于注入基本类型和String类型的数据
属性:
value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
SpEL的写法:${表达式}
用于改变作用范围的
他们的作用就和在bean标签中使用scope属性实现的功能是一样的
Scope
作用:用于指定bean的作用范围
属性:
value:指定范围的取值。常用取值:singleton prototype
和生命周期相关 (了解)
他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的
PreDestroy
作用:用于指定销毁方法
PostConstruct
作用:用于指定初始化方法
通过配置类替换掉xml文件,完全使用注解配置
ApplicationContext ac=new AnnotationConfigApplicationContext(config.class);
获得容器对象,传入一个由@Configuration注解配置过的类的字节码
@Configuration表示此类是一个配置类
@@ComponentScan(basePackages = "com.itheima")表示要扫描的包 其中basePackages可以省略,也可以用value替代
@Bean(name=“”)将对象存入Spring容器中,key为name中的名称
@Scope("prototype")设置对象为多例对象
实际开发中应遵循怎么方便怎么配置,一般来说自己写的类使用注解配置,jar包中的类使用xml文件配置
当@Qualifier作为方法参数的注解时,可以不依靠@AutoWride独立存在
public QueryRunner Createrunner(@Qualifier("ds1") DataSource dataSource ){
return new QueryRunner(dataSource);
}
spring整合junit
1.导入Spring-test坐标
2.@Runwith注解将junit中的main方法替换成spring中的main方法
@RunWith(SpringJUnit4ClassRunner.class)
3.告知spring运行器spring和ioc创建是基于注解还是xml的,并提供位置
xml文件创配置:locations
@ContextConfiguration(locations=“classpath:bean.xml”)
classes:指定配置类所在位置
@ContextConfiguration(classes = config.class)
4.使用的spring版本在5.0以上的话要求junit版本在4.1.2上,不然会报错
spring中基于XML的AOP配置步骤
1、把通知Bean也交给spring来管理
2、使用aop:config标签表明开始AOP的配置
3、使用aop:aspect标签表明配置切面
id属性:是给切面提供一个唯一标识
ref属性:是指定通知类bean的Id。
4、在aop:aspect标签的内部使用对应标签来配置通知的类型
我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知
aop:before:表示配置前置通知
method属性:用于指定Logger类中哪个方法是前置通知
pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
<?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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 配置srping的Ioc,把service对象配置进来-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<!--spring中基于XML的AOP配置步骤
1、把通知Bean也交给spring来管理
2、使用aop:config标签表明开始AOP的配置
3、使用aop:aspect标签表明配置切面
id属性:是给切面提供一个唯一标识
ref属性:是指定通知类bean的Id。
4、在aop:aspect标签的内部使用对应标签来配置通知的类型
我们现在示例是让printLog方法在切入点方法执行之前之前:所以是前置通知
aop:before:表示配置前置通知
method属性:用于指定Logger类中哪个方法是前置通知
pointcut属性:用于指定切入点表达式,该表达式的含义指的是对业务层中哪些方法增强
切入点表达式的写法:
关键字:execution(表达式)
表达式:
访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)
标准的表达式写法:
public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
访问修饰符可以省略
void com.itheima.service.impl.AccountServiceImpl.saveAccount()
返回值可以使用通配符,表示任意返回值
* com.itheima.service.impl.AccountServiceImpl.saveAccount()
包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
* *.*.*.*.AccountServiceImpl.saveAccount())
包名可以使用..表示当前包及其子包
* *..AccountServiceImpl.saveAccount()
类名和方法名都可以使用*来实现通配
* *..*.*()
参数列表:
可以直接写数据类型:
基本类型直接写名称 int
引用类型写包名.类名的方式 java.lang.String
可以使用通配符表示任意类型,但是必须有参数
可以使用..表示有无参数均可,有参数可以是任意类型
全通配写法:
* *..*.*(..)
实际开发中切入点表达式的通常写法:
切到业务层实现类下的所有方法
* com.itheima.service.impl.*.*(..)
-->
<!-- 配置Logger类 -->
<bean id="logger" class="com.itheima.utils.Logger"></bean>
<!--配置AOP-->
<aop:config>
<!--配置切面 -->
<aop:aspect id="logAdvice" ref="logger">
<!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
<aop:before method="printLog" pointcut="execution(* com.itheima.service.impl.*.*(..))"></aop:before>
</aop:aspect>
</aop:config>
</beans>
切入点表达式的写法:
关键字:execution(表达式)
表达式:
访问修饰符 返回值 包名.包名.包名...类名.方法名(参数列表)
标准的表达式写法:
public void com.itheima.service.impl.AccountServiceImpl.saveAccount()
访问修饰符可以省略
void com.itheima.service.impl.AccountServiceImpl.saveAccount()
返回值可以使用通配符,表示任意返回值
* com.itheima.service.impl.AccountServiceImpl.saveAccount()
包名可以使用通配符,表示任意包。但是有几级包,就需要写几个*.
* *.*.*.*.AccountServiceImpl.saveAccount())
包名可以使用..表示当前包及其子包
* *..AccountServiceImpl.saveAccount()
类名和方法名都可以使用*来实现通配
* *..*.*()
参数列表:
可以直接写数据类型:
基本类型直接写名称 int
引用类型写包名.类名的方式 java.lang.String
可以使用通配符表示任意类型,但是必须有参数
可以使用..表示有无参数均可,有参数可以是任意类型
全通配写法:
* *..*.*(..)
实际开发中切入点表达式的通常写法:
切到业务层实现类下的所有方法
* com.itheima.service.impl.*.*(..)
通用化切入点表达式
<aop:pointcut id="ser"
expression="execution(* com.itheima.service.impl.*.*(..))"> </aop:pointcut>
写在<<aop:aspect>标签前:
作为公共的,所有<aop:aspect>标签都可以引用
写在<aop:aspect>标签内:
只能在此标签内部使用
spring环绕通知
问题:
在xml文件中配置了环绕通知之后,切入点方法没有执行,而通知方法执行了。
分析:
代码中没有明确的切入点方法调用。
解决:
Spring框架为我们提供了一个接口:ProceedingJoinPoint。该接口有一个方法proceed(),此方法就相当于明确调用切入点方法。
该接口可以作为环绕通知的方法参数,在程序执行时,spring框架会为我们提供该接口的实现类供我们使用。
spring中的环绕通知: 它是spring框架为我们提供的一种可以在代码中手动控制增强方法何时执行的方式。
public Object aroundPringLog(ProceedingJoinPoint pjp){ //返回Object类型的切入点方法的返回值
Object returnValue = null; //定义业务层方法(切入点方法)执行后的返回值
try{
Object[] args = pjp.getArgs(); //获取业务层方法(切入点方法)的参数
System.out.println("Logger类中的前置方法执行了");
returnValue = pjp.proceed(args);//调用业务层方法(切入点方法)并传入参数
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置");
return returnValue;
}catch (Throwable t){
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常");
throw new RuntimeException(t);
}finally {
System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终");
}
}
使用注解配置aop
xml文件中
//配置扫描注解
<context:component-scan base-package="com.zhonghuan"></context:component-scan>
//配置开启注解aop
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
切面类中
//将此类存入核心容器中
@Component("logger")
//表示当前类是一个切面类
@Aspect
//新建一个方法用于配置通用化切入点表达式
@Pointcut("execution(* com.zhonghuan.Service.impl.AccountServiceimpl.*(..) )")
public void pc1(){}
//前置方法
@Before("pc1()")
//后置方法
@AfterReturning("pc1()")
//异常方法
@AfterThrowing("pc1()")
//最终方法
@After("pc1()")
//配置环绕方法
@Around("pc1()")
由于单独配置四个方法时,spring在方法调用顺序上先调用后置方法/异常方法 后调用最终方法,所以建议要么使用xml文件配置四个方法,要么使用注解配置环绕方法
切面类案例
package com.zhonghuan.utils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
//将类存入spring容器
@Component("logger")
//表示类是个切面类
@Aspect
public class logger {
// 配置通用切入点
@Pointcut("execution(* com.zhonghuan.Service.impl.AccountServiceimpl.*(..) )")
public void pc1(){
}
//前置方法
@Before("pc1()")
public void beforeprint(){
System.out.println("日记记录开始");
}
//最终方法
@After("pc1()")
public void afterprint(){
System.out.println("日志记录结束");
}
//配置异常方法
@AfterThrowing("pc1()")
public void exceptionprint(){
System.out.println("异常方法");
}
//配置后置方法
@AfterReturning
public void commitprint(){
System.out.println("提交方法开始");
}
//配置环绕方法
@Around("pc1()")
public Object aroundprintlog(ProceedingJoinPoint pjp){
Object[] args = pjp.getArgs(); //获取业务层方法(切入点方法)的参数
Object returnvalue=null; //定义业务层方法(切入点方法)执行后的返回值
try {
System.out.println("前置方法被执行");
returnvalue = pjp.proceed(args);
System.out.println("后置方法被执行");
return returnvalue;
} catch (Throwable throwable) {
System.out.println("异常方法被执行");
throw new RuntimeException(throwable);
}finally {
System.out.println("最终方法被执行");
}
}
}
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"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置spring创建容器时要扫描的包-->
<context:component-scan base-package="com.zhonghuan"></context:component-scan>
<!-- 配置spring开启注解AOP的支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
来源:CSDN
作者:青殒
链接:https://blog.csdn.net/qq_42446990/article/details/104329183