学习Java框架 Spring
Java Spring框架
- 简介
- Spring是一个开源框架、一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。相当于一个容器 工厂, 可以将所有对象创建和依赖关系维护, 交由 Spring 管理 。
- 体系结构
如果作为一个整体,这些模块为你提供了开发企业应用所需的一切。但你不必将应用完全基于Spring框架。你可以自由地挑选适合你的应用的模块而忽略其余的模块。
Spring简单使用
步骤·:
- 1、导包 引入spring依赖的jar文件
- 解压后的文件夹:
- docs :API 和开发规范.
- libs :jar 包和源码.
- schema :约束.
- jar 包
- spring-beans-4.3.6.jar 所有应用都要用到的,它包含访问配置文件、创建和管理 bean(java对象)及进行 Inversion of Control / Dependency Injection(属性赋值)(IoC/DI)操作相关的所有类
- spring-context-4.3.6.jar Spring 供在基础 IoC 功能上的扩展服务,此外还 供许多企业级服务的支持 , 如邮件服务(SpringMail)、 任务调度(SpringTest)、JNDI 定位、EJB 集成、远程访问、缓存以及各种视图 层框架(springMVC)的封装等。
- spring-core-4.3.6.jar 包含 Spring 框架基本的核心工具类,Spring 其它组件要都要使用到这个包里 的类 , 是其它组件的基本核心。
- spring-expression-4.3.6.jar Spring 表达式语言
- commons-logging-1.2.jar 第三方的主要用于处理日志
- 解压后的文件夹:
- 2、创建一个对象 并提供set和get方法 比如User
- 3、xml配置注册对象到容器
- 建立xml文件,(applicationContext.xml)
- 配置文件头信息
- 注册对象:< bean id=“user” class=“beike.spring.pojo.User”></ bean> 相当于直接new User() 无参 图:
- 属性解析:
- 将User对象交给spring容器管理 ,其中name任意,class为全包名
- class属性:被管理对象的完整类名
- name属性:给被管理的对象起个名字,根据该名称获得对象可以重复,可以使用特殊字符
- id属性:与name属性一模一样名称不可重复,不能使用特殊字符 所以尽量使用name属性
- 4、代码测试
Spring的工厂(容器) 加载的三种方式
- 方法一 在类路径下寻找配置文件来实例化容器 即src目录下的 等
- //如果只有一个配置文件,一次加载一个容器 ApplicationContext applicationContext = new ClassPathXmlApplicationContext(“applicationContext.xml”);
- // 如果有多个配置文件,定义成数组一次可以加载多个 spring 容器 ApplicationContext ac = new ClassPathXmlApplicationContext(new String[] {“com/offcn/applicationContext.xml” , “com/offcn/beans.xml”});
- //或者是使用通配符加载: ApplicationContext ctx=new ClassPathXmlApplicationContext(“com/offcn/*.xml”);
- 方法二 从硬盘绝对路径下加载配置文件
- ApplicationContext ctx = new FileSystemXmlApplicationContext(“recourse/applicationContext.xml”); //当前项目路径加载单个配置文件
- ApplicationContext ctx = new FileSystemXmlApplicationContext(“D:/project/bean.xml”);//根据具体路径加载文件
- // 如果有多个配置文件,定义成数组一次可以加载多个 spring 容器 ApplicationContext ac = new FileSystemXmlApplicationContext(new String[] {“D:\workspaceSpring\SpringBean\beans.xml”});
- 方法三 (过时) 使用 BeanFactory
- BeanFactory beanfactory = new XmlBeanFactory(new FileSystemResource(“D:\dev\work\springDemo\recourse\applicationContext.xml”));
- 注意点:
- BeanFactory :是在 getBean 的时候才会生成类的实例
- AlicationContext 默认在加载 applicationContext.xml(容器启动)时候就会创建类的实例
IOC:控制反转 由 Spring IOC 容器来负责对象的生命周期和对象之间的关系
Spring创建对象的三种方式 (无参示例):
- 方式一: 空参构造方式(最主要方式):
- xml文件beans里面配置 :< bean id=“user” class=“beike.spring.pojo.User”></ bean>
- 方式二: 使用静态工厂方法实例化 ( 简单工厂模式 )
- < !-- 通过工厂的静态方法来获取对象 -->
< bean name=“userStaticFactory” class=“com.ujiuye.day04.ioc.factory.UserStaticFactory”
factory-method=“getUser”></ bean>
- < !-- 通过工厂的静态方法来获取对象 -->
- 方式三: 使用实例工厂方法实例化 ( 工厂方法模式 )
- < !-- 通过工厂的非静态方法获取对象 -->
< bean name=“UserFactory” class=“com.ujiuye.day04.ioc.factory.UserFactory”></ bean>
< bean name=“getUserByUserFactory” factory-bean=“UserFactory”
factory-method=“getUser”></ bean>
- < !-- 通过工厂的非静态方法获取对象 -->
- 注意:class 一定要是类,不能使用接口,因为接口不能被实例化。
关于配置文件解析(applicationContext.xml):
- bean元素属性
DI:即依赖注入, 就是由IOC容器在运行期间, 动态地将某种依赖关系注入到对象之中。
属性注入 :
1、set方法注入 (前提是set注入之前该对象提供setter方法) 子标签:property
2、构造函数注入 (前提是在类中提供匹配的构造方法) 子标签:constructor-arg
3、使用注解实现注入 使用 @Autowired 或 @Resource 注解方式进行装配
4、注解实现装配Bean
-
1、set方法注入使用示例:
- Car类
- xml文件配置
- Car类
-
2、构造函数注入使用示例:
- User类
- xml文件配置
- User类
-
3、复杂类型注入: 数组、List集合、Map集合、 Properties配置文件:
- ComplexBean类:
- xml文件
- ComplexBean类:
-
4、使用注解实现注入 使用 @Autowired 或 @Resource 进行装配使用步骤:
-
1、引入context命名空间 需要在xml配置文件中配置以下信息
- 注意:< context:annotation-config/> 标签 这个配置隐式注册了多个对注解进行解析处理的处理器:
- 对注解进行解析处理的处理器
- AutowiredAnnotationBeanPostProcessor
- CommonAnnotationBeanPostProcessor
- PersistenceAnnotationBeanPostProcessor
- RequiredAnnotationBeanPostProces- sor
- 注意:< context:annotation-config/> 标签 这个配置隐式注册了多个对注解进行解析处理的处理器:
-
2、使用注解@autowired 或者注解@Resource 标注在属性上 或者 标注在 set 方法上
-
3、代码测试
-
-
关于注解@autowired 和 注解@Resource 的用法:
-
@autowired
- 使用注解 @autowired 标注在属性上
- 获取该注解标注的字段的类型—Car类型
- 以该类型为条件到spring容器(beans.xml文件)中去查找bean的id节点的类型是 Car 类型 。 比如说:文件上有< bean name=“car” class=“com.ujiuye.day04.annotation.pojo.Car”>
- 找到以后,获取该节点对应的对象,利用反射直接为personDao变量赋值
所以注解 @autowired 标注在属性上可以不用set方法
- 使用注解 @autowired 标注在 set 方法上
- 获取 setCar() 方法的参数的类型 —Car 类型
- 以该类型为条件到spring容器(beans.xml)中去查找bean的id节点的类 型是Car 类型 .
- 找到以后 , 获取该节点对应的对象 , 把该对象作为实参传递给该 setCar(Car car) 的形参 .
- 使用注解 @autowired 标注在属性上
-
@Resource
- 使用注解 @Resource 标注在属性上
- 如果没有指定 name 属性 则获取该注解标注的字段值—car3
- 以该字段值为条件到 spring 容器 (beans.xml) 中去查找 bean 的 id 节点的值是 car3 的节点
- 找到以后,获取该节点对应的对象, 利用反射直接为car3变量 赋值
- 如果没有找到.并且按照默认的名称找不到依赖对象时, @Resource 注解会回退到按类型装配
- 获取该注解标注的字段类型 --Car 以该类型为条件到spring容器(xml文件)中去查找bean的节点的 类型是 Car 类型的对象 找到以后,获取该节点对应的对象,利用反射直接为car3 变量 赋值
- 如果指定 name 属性 只能按名称装配
- 获取name属性的值
- 以该值为条件到spring容器(beans.xml)中去查找bean的id节点的值
- 找到以后 , 获取该节点对应的对象 , 把该对象作为实参传递给该 setCar(Car Car) 的形参 .
- 如果不存在该名称 , 抛出异常
- 如果没有指定 name 属性 则获取该注解标注的字段值—car3
- 使用注解 @Resource 标注在属性上
- 使用注解 @Resource 标注在 set 方法上
- 如果没有指定name属性
- 获取setCar()方法的属性名—car
- 以该属性名为条件到spring容器(xml文件)中去查找bean的id节点的值是 car 的节点
- 找到以后 , 获取该节点对应的对象 , 把该对象作为实参传递给该 setPersonDao( PersonDao personDao) 的形参 .
- 如果没有找到.并且按照默认的名称找不到依赖对象时,@Resource注解会回退到按类型装配
- 获取setPersonDao()方法的参数类型—PersonDao
- 以该类型为条件到spring容器(beans.xml)中去查找bean的节点的类型是 PersonDao 类型对象
- 找到以后 , 获取该节点对应的对象 , 把该对象作为实参传递给该 setPersonDao(
PersonDao personDao) 方法的形参
- 如果没有指定name属性
- 如果指定 name 属性 只能按名称装配
- 获取name属性的值
- 以该值为条件到spring容器(beans.xml)中去查找bean的id节点的值
- 找到以后 , 获取该节点对应的对象 , 把该对象作为实参传递给该 setCar(Car Car) 的形参 .
- 如果不存在该名称 , 抛出异常
注解实现装配Bean :
- 简介:
- 1、Spring3.0 为我们引入了组件自动扫包 机制,它可以在类路径底下寻找标注了 @ Component、@Service、@Controller、@Repository 注解的类,并把这些类纳入进 spring 容器中管理。
- 2、功能介绍
- @Service 用于标注业务层组件.
- @Controller 用于标注控制层组件(如 struts 中的 action)
- @Repository 用于标注数据访问组件,即 DAO 组件。
- @Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
- 2、功能介绍
- 1、Spring3.0 为我们引入了组件自动扫包 机制,它可以在类路径底下寻找标注了 @ Component、@Service、@Controller、@Repository 注解的类,并把这些类纳入进 spring 容器中管理。
使用步骤:
- 1、引入context命名空间 需要在xml配置文件中配置以下信息:
- 2、将相应的注解标注在实现类的上面
- 3、代码测试
AOP:是Spring框架面向切面的编程思想
- AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。
AOP 代理模式 :JDK动态代理(主要使用)、 cglib代理
- 简介:
- 代理模式 : 代理模式的英文叫做 Proxy 或 Surrogate,中文都可译为”代理“,所谓代理, 就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客 户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介 的作用 .
- 使用代理对象访问目标对象(优势:目标对象专注于实现目标对象需要的业务操作,代理对象用来添加其他的操作)
- 注意:开发时尽量使用接口的编程,
- (1) 对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统。
- (2) 标记为 final 的方法不能够被通知。spring 是为目标类产生子类。任何需要被通知的方法都被复写,将通知织入。final 方法是不允许重写的。
- (3) spring 只支持方法连接点,不支持属性的连接点
- JDK 动态代理 :必须要实现接口,才能产生代理对象,如果没有接口不能使用动态代理技术
- cglib代理 (没有实现任何接口):第三方代理技术,可以对任何类实现代理,
原理:对目标对象进行继承代理,如果目标被final修饰,则无法被cglib代理。
准备通知:
AOP 配置
- 要进行 AOP 编程,首先我们要在 spring 的配置文件中引入 aop 命名空间: :
- Spring 提供了两种切面使用方式,实际工作中我们可以选用其中一种:
- 基于 XML 配置方式进行 AOP 开发。
- 基于注解方式进行 AOP 开发。
AOP(基于xml文件配置):
- 1、导入spring相关的jar包
- 2、准备目标对象
-
- 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 id="userService" class="beike.spring.day2.UserServiceImpl"></bean>
</beans>
- 测试:
public class App {
public static void main(String[] args) {
// 直接访问目标对象
// 使用代理对象访问目标对象,当在 spring 的容器中添加 <aop>
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService)ac.getBean("userService");
userService.saveUser(" 超级强 ", "123");
userService.updateUser(" 超级强 ", "123");
userService.deleteUser(" 超级强 ");
String str = userService.findUser();
System.out.println("str:"+str);
}
}
- 3、准备通知
- .
- 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型 (
- 环绕通知需要定义第一个参数为ProceedingJoinPoint类型, 它是 JoinPoint 的一个子类)。
- JoinPoint 接口提供了一系列有用的方法, * 比如 getArgs()(返回方法参数)、
- getThis()(返回代理对象)、
- getTarget()(返回目标)、
- getSignature()(返回正在被通知的方法相关信息)、
- toString() (打印出正在被通知的方法的有用信息)。
前置通知
- **前置通知示例:**继续使用刚刚的例子,新增切面类BeforeSecurity
public class BeforeSecurity {
public void checkSecurity(JoinPoint joinPoint){
System.out.println(" 正在执行验证 ...");
Object [] args = joinPoint.getArgs();
if(args!=null && args.length>0){
for(Object o:args){
System.out.println(" 参数:"+o);
}
}
System.out.println(" 代理对象:"+joinPoint.getThis(). getClass());
System.out.println(" 目标对象:"+joinPoint.getTarget(). getClass());
System.out.println(" 访问目标对象方法的名称:"+joinPoint. getSignature().getName());
System.out.println("spring容器中定义切入点的表达式: "+joinPoint.toString());
}
}
- 前置通知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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="userService" class="beike.spring.day2.UserServiceImpl"></bean>
<bean id=" beforeSecurity " class="beike.spring.day2.BeforeSecurity"></bean>
<!-- spring的aop编程,所有的操作(切面、通知、切入点)都要放置到 aop:config -->
<aop:config>
<!--
声明切入点
id:切入点的惟一标识 expression:切入点的表达式语言,指定项目中哪个类哪个方法作为切入点 -->
<aop:pointcut id="save" expression="execution(* beike.spring.day2.UserServiceImpl.saveUser(..))" />
<aop:pointcut id="update" expression="execution(* beike.spring.day2.UserServiceImpl.updateUser(..))" />
<!--定义个切面,此时切面的类具有了灵魂 id:惟一标识 ref:注入对象-->
<aop:aspect id="aa" ref=" beforeSecurity ">
<!--
定义通知(切入点要做的事情) 前置通知:在访问目标对象方法之前,先执行通知定义的方法
特点:如果代理对象(切面)中的方法(通知)抛出异常,此时不会执行目标对象通知
* pointcut-ref:注入切入点,这样才能让切入点关联
* method: 指定切面中定义的通知的方法 -->
<aop:before pointcut-ref="save" method="checkSecurity"/>
<aop:before pointcut-ref="update" method="checkSecurity"/>
</aop:aspect>
</aop:config>
</beans>
- 重新运行
后置通知:
- 后置通知和前置通知的配置是一样的,后置通知为:< aop:after-returning />
新增切面类AfterSecurity
public class AfterSecurity {
public void checkSecurity(JoinPoint joinPoint,Object returnValue){
System.out.println(" 正在执行验证 ...");
Object [] args = joinPoint.getArgs();
if(args!=null && args.length>0){
for(Object o:args){
System.out.println(" 参数:"+o);
}
}
System.out.println(" 代理对象:"+joinPoint.getThis(). getClass());
System.out.println(" 目标对象:"+joinPoint.getTarget(). getClass());
System.out.println(" 访问目标对象方法的名称:"+joinPoint. getSignature().getName());
System.out.println("spring 容 器 中 定 义 切 入 点 的 表 达 式: "+joinPoint.toString());
System.out.println(" 目标对象方法的返回值:"+returnValue);
}
}
- 后置通知的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:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<bean id="userService" class="beike.spring.day2.UserServiceImpl"><