Spring入门(二)— IOC注解、Spring测试、AOP入门
一、Spring整合Servlet背后的细节
1. 为什么要在web.xml中配置listener
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
配置listener主要是为了捕获项目发布 | 服务器启动的契机 ,为了解析xml , 创建工厂。 这个listener是spring官方提供的,里面已经具备了解析xml 和 创建工厂的代码。
2. 为什么要在web.xml中配置context-param
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
正如上面所说的,listener捕获到了项目发布的契机,进而去创建工厂。但是创建工厂需要解析xml 。 spring的这个监听器里面,默认会到WEB-INF/applicationContext.xml. 如果不想放置到这个位置,可以通过一个context-param来告诉spring,我们的配置文件在哪里。
classpath
表示这个文件是位于类路径底下。 classes目录
3. 为什么使用工具类也能拿到工厂,到底工厂放在了哪里?
public class ContextLoaderListener extends ContextLoader implements ServletContextListener { //项目一发布,就执行
public void contextInitialized(ServletContextEvent event) {
//创建工厂
initWebApplicationContext(event.getServletContext());
}
}
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
...
if (this.context == null) {
//创建工厂
this.context = createWebApplicationContext(servletContext);
} //把创建好的工厂,存储到作用域
//servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,
this.context);
...
}
//spring为了简化程序员获取工厂的工作, 就提供了一个工具类,其实这个工具类就是对取值的代码进行封装
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); //ApplicationContext context = (ApplicationContext) getServletContext().getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
二、IOC注解
1. 注解入门
导入jar包
spring-aop-xxx.jar
导入约束
<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">
在xml里面打开注解扫描开关
<!-- 告诉spring要去解析类,因为类上有注解 -->
<context:component-scan base-package="com.pri.service.impl"/>
在托管的类上打注解
@Component("us")
public class UserServiceImpl implements UserService {
...
}
问工厂要实例对象
//创建工厂 创建工厂,需要解析xml ,所以要传递进去xml文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //问工厂要实例对象
UserService userService = (UserService) context.getBean("us"); //调用方法
userService.save(); //关闭工厂 : 以后我们几乎不会关闭工厂。
((AbstractApplicationContext) context).close();
2. 注解创建对象
/*
1. @Component组件,表示要托管这个类,让spring创建这个类的实例。 括号里面的us 其实就是id标识符
2. @Component 是通用的注解, 对任何托管的类都可以使用,但是spring为了迎合三层架构,所以对每一层
也给出了具体的注解。
Action --- @Controller
Service --- @Service
Dao --- @Repository :仓库,
建议: 如果以后托管三层中的类,请使用具体对应的注解,如果托管的是普通的其他类。@Component
3. 默认生成的实例还是单例,如果想做成多例,那么还得添加一个注解
@Scope("prototype")
4. @PostConstruct //初始化实例的时候调用
@PreDestroy //销毁实例之前,调用
5. 如果使用注解托管某一个类,不写属性值,那么默认的id标识符就是类的名字(首字母是小写) userServiceImpl
6.<!-- 如果想要扫描多个包,就写一个通用的前缀即可 -->
<context:component-scan base-package="com.pri"/>
*/
3. DI注解开发(注入对象)
使用注解来完成依赖注入。 一般注解注入,它针对的点是对象的注入。 spring针对对象的注入,提供了两个注解
@Resource
和@Autowired
常用的注解就两个 @Resource & @Autowired
@Resource(name="ud") 根据给定的标记找到对应的类,创建对象,注入进来。
@Autowired 自动装配,会找到对应的实现类创建对象,注入进来。但是如果存在多个实现,那么会抛出异常
@Repository("ud")
public class UserDaoImpl implements UserDao {
} public class UserServiceImpl implements UserService {
@Resource(name="ud") //spring拿着ud找到具体的类,然后创建实例,注入进来。
private UserDao userDao;
...
}
----------------------------------------------------------
public class UserServiceImpl implements UserService {
@Autowired //自动装配 根据注入的接口类型找到对应的实现类,注入进来。
private UserDao userDao;
...
}
4. xml和注解混合使用
在项目里面,使用xml和注解来完成Spring 的配置。
xml : 负责完成IOC (对象的创建)
注解 : 负责完成DI (属性的注入)
xml托管类
<context:component-scan base-package="com.pri"/>
<bean id="ud" class="com.pri.dao.impl.UserDaoImpl"></bean>
<bean id="us" class="com.pri.service.impl.UserServiceImpl"></bean>
注解完成注入:
public class UserServiceImpl implements UserService {
@Resource(name="ud")
private UserDao userDao;
}
三、Spring测试
导入jar包
spring-test-xxx.jar
托管业务逻辑类,不管是用xml还是注解都可以
<bean id="us" class="com.pri.service.impl.UserServiceImpl"></bean>
在测试类上打上注解 ,给测试类的成员变量注入值
//spring扩展了junit的运行环境,除了有测试功能之外,还在里面定义了创建工厂的代码
@RunWith(SpringJUnit4ClassRunner.class)
//告诉spring的测试环境,配置文件在哪里
@ContextConfiguration("classpath:applicationContext.xml")
public class TestUserService { //测试类里面出现的注解,不用打开扫描开关。因为这个测试环境里面,它会解析这个测试类的注解。
@Autowired
private UserService userService;
@Test
public void testSave(){
userService.save();
}
}
四、AOP
1. 什么是AOP , 它有什么用?
AOP(Aspect Oriented Programming,面向切面编程),可以说是OOP(Object Oriented Programing,面向对象编程)的补充和完善。OOP更多的是侧重于上下间的关系(继承关系 、实现关系) , OOP很难体现左右间的关系。 核心: 在不改动源码的前提下,对原有功能能完成扩展 | 升级
2. AOP的底层原理
aop不改源码,但是能够扩展和升级代码。 能够做成这个事情,只有三种解决手法 :
装饰者模式
,静态代理
、动态代理
。 AOP 选择的是动态代理 , 装饰者模式和静态代理,要求我们必须写出来装饰类和代理类。 动态代理的实现机制,有两种:基于JDK的动态搭理
、基于Cglib的动态代理
1. 动态代理的实现机制
基于JDK的动态代理
如果哪一个真实类有实现接口,那么就采用这种方式,创建出来接口的另一个实现类作为代理类
//jdk动态代理
@Test
public void testJDKPorxy(){ //UserService userService = new UserServiceImpl();
//userService.save(); //1. 先创建真实对象
final UserService userService = new UserServiceImpl(); //2. 创建代理对象
UserService proxyObj = (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(), //类加载器,真实类用什么,代理类就用什么
userService.getClass().getInterfaces(), //真实类实现什么接口,代理类也实现什么接口
new InvocationHandler() {//回调函数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke~");
//userService.save(); if(method.getName().equals("save")){
Logger.log();
} //以不变应万变。 反射调用
return method.invoke(userService, args);
}
}); //3. 让代理对象干活
proxyObj.save(); //代理对象。save() ----> 真实对象.save();
}
基于Cglib动态代理
如果真实类是一个普通类,没有实现接口,那么就采用这种方式, 创建出来真实类的子类作为代理类。
//cglib动态代理
@Test
public void testCglibPorxy(){
//1. 一定要有真实对象
final ProductService productService = new ProductService();
//2. 创建代理
Enhancer enhancer = new Enhancer();
//设置父类是谁
enhancer.setSuperclass(ProductService.class);
//设置回调
enhancer.setCallback(new MethodInterceptor() {
/*
* arg0 :代理对象
* arg3 : 方法的代理
*
* 一般这两不用。
*
* arg1 : 方法引用
* arg2 :参数
*/
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
Logger.log();
return arg1.invoke(productService, arg2);
}
}); //创建代理对象
ProductService proxyObj = (ProductService) enhancer.create();
proxyObj.save();
}
3. AOP术语
4.AOP的入门
Spring的AOP其实已经准备好了创建代理的代码。只是不知道的是要创建谁的代码。哪些方法需要被增强。我们需要通过配置的形式告诉spring。
定义业务逻辑类
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("调用了UserServiceImpl 的 save方法");
}
}
定义增强类
public class Logger {
public static void log(){
System.out.println("输出日志了~~");
}
}
导入jar包
a. 导入 spring必须的jar
b. 额外导入:
spring-aop-xx.jar,spring-aspect-xx.jar
面向切面过程中,Spring AOP是遵循了AOP联盟的规范实现的,所以需要有AOP联盟的接口包
aopalliance-x.x.jar,接口包依赖aspectjweaver-x.x.x.jar
xml中配置
要导入aop的约束
让spring托管 业务逻辑类 和 增强类
<bean id="us" class="com.pri.service.impl.UserServiceImpl" ></bean>
<bean id="logger" class="com.pri.util.Logger" ></bean>
配置AOP
<!-- 2. 开始配置aop -->
<aop:config>
<!-- 配置切入点 expression 表达式 '
execution(* com.xyz.myapp.service.*.*(..))
execution 固定写法
第一个* 代表任意返回值
com.xyz.myapp.service : 包名
第二个* 包下的任意类
第三个* 类中的任意方法
(..) : 任意参数
saveUser
saveOrder
-->
<aop:pointcut expression="execution(* com.pri.service.impl.*.*(..))" id="aa"/>
<!-- 配置增强
根据aa的表达式找到的方法,都给他们做前置增强,增强的功能是log方法
-->
<aop:aspect ref="logger">
<aop:before method="log" pointcut-ref="aa"/>
</aop:aspect>
</aop:config>
5. AOP 增强
<aop:config>
<aop:pointcut expression="execution(* com.pri.service.impl.*.*(..))" id="pointcut01"/>
<!-- 真正用aop来扩展一个功能,比较少。 除非是我们想扩展第三方jar包。
aop的思想无处不在:struts 拦截器 (就是AOP) --> <!-- 配置切面aspect -->
<aop:aspect ref="logger">
<!-- 前置增强 -->
<!-- <aop:before method="log" pointcut-ref="pointcut01"/> --> <!-- 最终增强 -->
<!-- <aop:after method="log" pointcut-ref="pointcut01"/> --> <!-- 后置增强 -->
<!-- <aop:after-returning method="log" pointcut-ref="pointcut01"/> --> <!-- 异常增强 -->
<!-- <aop:after-throwing method="log" pointcut-ref="pointcut01"/> --> <!-- 环绕增强 -->
<!-- <aop:around method="around" pointcut-ref="pointcut01"/> -->
<aop:before method="log" pointcut-ref="pointcut01"/>
<aop:after-returning method="log" pointcut-ref="pointcut01"/>
</aop:aspect>
</aop:config>
Spring入门(二)— IOC注解、Spring测试、AOP入门的更多相关文章
- Spring第二天——IOC注解操作与AOP概念
大致内容 spring的bean管理(注解实现) AOP原理 log4j介绍 spring整合web项目的演示 一.spring注解实现bean管理 注解: 代码中一些特殊的标记,使用注解也可以完成一 ...
- (转)使用Spring的注解方式实现AOP入门
http://blog.csdn.net/yerenyuan_pku/article/details/52865330 首先在Eclipse中新建一个普通的Java Project,名称为spring ...
- Spring顾问、IOC注解和注解增强
一.顾问 通知的一种表现方式(顾问包装通知/增强) Advisor: 名称匹配方法: NameMecthMethodPointcutAdvisor 1.定义了一个业务类 package cn.spri ...
- Spring Boot 二十个注解
Spring Boot 二十个注解 占据无力拥有的东西是一种悲哀. Cold on the outside passionate on the insede. 背景:Spring Boot 注解的强大 ...
- Spring源码-IOC部分-Spring是如何解决Bean循环依赖的【6】
实验环境:spring-framework-5.0.2.jdk8.gradle4.3.1 Spring源码-IOC部分-容器简介[1] Spring源码-IOC部分-容器初始化过程[2] Spring ...
- Spring框架学习之注解配置与AOP思想
上篇我们介绍了Spring中有关高级依赖关系配置的内容,也可以调用任意方法的返回值作为属性注入的值,它解决了Spring配置文件的动态性不足的缺点.而本篇,我们将介绍Spring的又一大核心 ...
- Spring学习笔记6——注解方式测试
需要下载junit-4.12.jar和hamcrest-all-1.3.jar,将下载好的包导入到项目当中. 修改TestSpring, 并运行1. @RunWith(SpringJUnit4Clas ...
- Spring(二):Spring框架&Hello Spring
Spring是一个开源框架,是为了解决企业应用程序开发复杂性而创建的.框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件,同时为J2EE应用程序开发提供集成的框架. Spring 框架 ...
- Spring自学教程-IOC、DI、AOP(二)
一.spring的IOC-就是怎样使用spring来创建对象 二.springDI(依赖注入)-就是怎样给属性赋值 通过set方式赋值 以下我们只需要记住两点的赋值,基本类型和引用类型的赋值 基本类型 ...
- spring入门(二) 使用注解代替xml配置
1.导包(略) 2.applicationContext.xml如下: <?xml version="1.0" encoding="UTF-8"?> ...
随机推荐
- FTP枢轴攻击
简单来说,这是攻击者可以利用属于不同网络的那些系统的攻击. 本文作者:jishuzhain 对于这种攻击,攻击者需要利用主服务器来帮助攻击者将自己添加到本地网络中,然后攻击者就可以将客户端系统进行定位 ...
- angular核心原理解析2:注入器的创建和使用
上一课没有讲到创建注入器的方法createInjector. 此方法,会创建两种不同的注入器:第一种叫做providerInjector,第二种叫做instanceInjector.providerI ...
- Python的科学计算包matplotlib setup
回想起大学四年 专业一直使用matlab,然而我却没在PC上装成功过,以前懒于思考这种数学工具的作用,直到最近,大学同学研究生要毕业了,几经交流,和自己阅读了一些机器学习的教材之后,发觉科学计算包和画 ...
- Bootstrap Table使用方法详解
http://www.jb51.net/article/89573.htm bootstrap-table使用总结 bootstrap-table是在bootstrap-table的基础上写出来的,专 ...
- Spring aop+自定义注解统一记录用户行为日志
写在前面 本文不涉及过多的Spring aop基本概念以及基本用法介绍,以实际场景使用为主. 场景 我们通常有这样一个需求:打印后台接口请求的具体参数,打印接口请求的最终响应结果,以及记录哪个用户在什 ...
- 利用Python爬取电影网站
#!/usr/bin/env python #coding = utf-8 ''' 本爬虫是用来爬取6V电影网站上的电影资源的一个小脚本程序,爬取到的电影链接会通过网页的形式显示出来 ''' impo ...
- java防范跨站脚本攻击(XSS)
网络中心提示网站有数目众多的跨站脚本攻击(XSS)漏洞,经过查看代码,认为是JSP中绑定变量是未经处理直接写入的,而且整个项目中这样的做法太多,因为是多年前的,不好一个个更改,参照网上资料,通过加fi ...
- P4859 已经没有什么好害怕的了
传送门 见计数想容斥 首先题目可以简单转化一下, 求 糖果比药片能量大的组数比药片比糖果能量大的组数多 $k$ 组 的方案数 因为所有能量各不相同,所以就相当于求 糖果比药片能量大的组数为 $(n+k ...
- spring定时任务详解
(一)在spring.xml里加入task的命名空间 xmlns:task="http://www.springframework.org/schema/task" http:// ...
- IT人生的价值和意义 感觉真的有了
为了做新闻APP,我居然短短一个月利用业余时间做了: 一个通用新闻采集器. 一个新闻后台审核网站. 一个通用采集器下载网站. 一个新闻微网站. 一个新闻APP, 而且还给新闻微网站和新闻 APP练就 ...