Day48-Spring-02
来源:互联网 发布:农友软件 编辑:程序博客网 时间:2024/06/05 03:53
一、IOC(控制反转)的注解
ioc的注解 – 要使用注解,就要导入spring-aop-4.2.9.RELEASE.jar
1. 入门
1. 导入jar包 除了导入基本的4个 和 日志包之外, 还要导入spring-aop-xx.jar2. 给指定的类上面打上注解(打上一个标记)
@Component("us")或@Component(value="us") //Component : 组件 spring 把我们这些托管的类,也看成是组件 @Component("us") public class UserServiceImpl implements UserService { }
3. 在applicationContext.xml中 导入context约束 ,然后打开注解的扫描开关 约束去哪里找,去Spring提供的html文档中去找,搜寻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要去扫描指定类上面有没有注解,如果有,就解析这个注解 --> <context:component-scan base-package="com.itheima"></context:component-scan><!-- 以下这种写法不常用。 这个开关虽然也是扫描的注解的开关,但是只能扫描在这个xml里面配置的bean 这些类 --><!-- <context:annotation-config></context:annotation-config> --></beans>
4. 获取实例的代码和以前一样。
@Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) context.getBean("userService"); userService.save(); ((AbstractApplicationContext) context).close(); }
2. IOC注解创建对象
spring针对ioc的注解,提供了通用的一个注解 @Component ,但是由于我们的web项目一般会使用分层的结构。 所以spring为了迎合这种趋势,也做出来每一层各自独立的注解。
@Controller : 标记 web层
@Service : 标记业务逻辑层
@Repository : 标记 dao层
spring做出来这三个独立的分层注解,也许未来会对它们进行增强、扩展,所以大家使用注解的话, 尽量使用 这三个。
- 如果注解里面不写内容, 那么默认也有一个id值, 就是类名的字符串,不过第一个字母小写
注解类:
@Servicepublic class UserServiceImpl{}
取值:
context.getBean("userServiceImpl");
- 默认生成的实例还是单例的,如果想生成多例,那么需要配置@Scope注解
@Service @Scope("prototype") public class UserServiceImpl{}
- 初始化方法以及销毁方法的设置
init-method: 表示初始化这个类时,会执行指定的方法
destroy-method : 销毁类实例时,会调用这个方法
<bean init-method="init" destroy-method="destroy"></bean>
(注意,只有在单例情况下,才会出现销毁的情况,就是关闭工厂。多例情况是不会执行销毁的方法的。) 这两个也可以使用注解来配置 @PostConstruct @PreDestroy 这两个配置是直接写在方法上面的
@Service("userService")@Scope("prototype")public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("userServiceImpl中的save方法执行了"); } @PostConstruct public void init(){ System.out.println("userServiceImpl中的init方法执行了"); } @PreDestroy public void destroy(){ System.out.println("userServiceImpl中的destroy方法执行了"); }}
3. 属性注入 – 侧重注入对象类型
使用注解属性注入:
因为这样注入普通属性,几乎没有可用性,还不如直接在声明的时候指定值
@Service("userService")@Scope("prototype")public class UserServiceImpl implements UserService { @Value("张三") private String username ;}
注入对象类型:
* @AutoWired
自动装配, spring会找到接口的实现类,然后创建实例注入进来
问题:如果该接口有多个实现,那么会抛出异常,无法注入;效率也没有Resource高
对象:
@Repository("userDao") public class UserDaoImpl implements UserDao {}使用: @Service("us") public class UserServiceImpl implements UserService { @Autowired private UserDao userDao ; }
- @Resource
根据指定的标签, 标识符去找到具体的类,然后注入进来。效率高
对象:
@Repository("userDao") public class UserDaoImpl implements UserDao {}
使用:
@Service("us") public class UserServiceImpl implements UserService { @Resource(name="userDao") private UserDao userDao ; }
@Qualifier (了解)
用来标记 自动装配的bean在spring IoC容器中的具体名称
这个注解标记比较少用,主要是在xml + 注解结合使用,并且在xml里面针对某一种类型bean , 声明了多了,存在了多个名称。
那么可以使用@Qqualifier来强制指定使用哪一个bean来构建实例。
<bean id="userDao" class ="com.itheima.dao.UserDao"> <property name="name" value="奥巴马"> </bean> <bean id="userDao2" class ="com.itheima.dao.UserDao"> <property name="name" value="特朗普"> </bean>
public class UserServiceImpl{ @Autowired @Qqualifier(name="userDao2") private UserDao userDao; }
xml和注解混合使用
1.使用xml来声明bean
<?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"> <bean id="userService" class="com.itheima.service.impl.UserServiceImpl" scope="prototype" init-method="init" destroy-method="destroy"> </bean> <bean id="user" class="com.itheima.domain.User" scope="prototype"> </bean> <context:component-scan base-package="com.itheima"></context:component-scan></beans>
2.使用注解来注入属性
public class UserServiceImpl implements UserService { /*@Resource(name="user")*/ @Autowired private User user;}public class User { @Value("张三") private String username; @Value("123") private String password;}
二、Spring测试
早前我们测试业务逻辑,一般都使用Junit 框架来测试, 其实在spring框架里面它也做出来了自己的一套测试逻辑, 里面是对junit进行了整合包装。本质上就是让我们在测试的时候少写工厂类的创建代码
使用Spring测试可以不用打开注解扫描开关, 当然如果要用的那些类上面有有注解, 就必须打开。只是测试类有注解的话,不用打开。 只有其他普通类,托管的类有注解,就必须打开注解扫描开关。
1. 导入jar包
spring -test-xxx.jar
- 在类上打注解
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(“classpath:applicationContext.xml”)
这两个注解就是完成工厂的构建工作,就是指定了由SpringJUnit4ClassRunner 去读取applicationContext 完成工厂构建工作
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext.xml")public class SpringTest { @Autowired private UserService userService; @Test public void test(){ userService.save(); }}
三、Spring AOP – Aspect Oriented Programmig面向切面编程
- AOP
Aspect Oriented Programming,面向切面编程 它是对OOP(面向对象编程)的一种补充,其实它的核心就是在不改动原来代码的基础上,可以进行扩展或者增强。
1. AOP的底层实现
动态代理
代理,不管是什么,一定需要先有真实对象。首先就创建一个真实对象出来
* 使用jdk的动态代理。proxy类 针对真实类,有实现接口 创建出来接口的实现类,然后创建实现类的对象作为代理对象* 使用cglib的动态代理。Enhancer类 如果那个真实类没有实现接口。 创建真实类的子类
- 使用JDK的动态代理
针对有实现接口的类。 创建出来接口的一个实现类,然后创建实现类的对象,作为代理对象
@Test public void testJDKProxy(){ //1. 创建真实对象 final UserService userService = new UserServiceImpl(); //2. 创建代理对象 UserService proxyService = (UserService) Proxy.newProxyInstance( userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //只要在外面用了代理对象调用方法,就一定回来到这个invoke里面,这里面要做的工作就是调用真实对象的方法。 //userService.save(); System.out.println("增强了日志输出功能"); return method.invoke(userService, args); } }); //3. 使用代理对象 proxyService.save(); }
- 使用Cglib动态代理
如果那个真实类没有实现接口, 使用cglib 。 创建出来真实类的子类, 然后创建子类的对象,作为代理对象。
@Test public void testCglibProxy(){ System.out.println("执行了cglib代理~~"); //1. 创建真实对象 final ProductService productService = new ProductService(); //2. 创建代理 Enhancer enhancer = new Enhancer(); //设置父类是谁 表示要做谁的子类出来作为代理 enhancer.setSuperclass(ProductService.class); //设置回调 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable { System.out.println("增强了日志输出功能2222"); return arg1.invoke(productService, arg2); } }); //创建代理对象 ProductService proxyService = (ProductService) enhancer.create(); proxyService.delete(); }
2. AOP的术语
连接点:Joinpoint
被增强的类中的所有方法都可以称之为连接点
切入点:Pointcut
具体被增强的方法
切面:Aspect
切面的解释应该是切入点和增强的结合 (这是侧重结果)。
织入:weaving
把增强应用到目标对象上来创建新的代理对象的过程
(这个注重过程)
增强:Advice
要扩展的功能。加入到切入点的方法
前置增强:增强在方法之前执行
后置增强:增强在方法之后执行
环绕增强:前后都执行增强
异常增强:只有方法出现异常才执行增强
最终增强:在最后执行。可以获取方法的返回值。
3. AOP入门
- 定义业务逻辑类
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. 额外导入: 4个包:
–这两个包是Spring提供的
spring-aop-4.2.9.RELEASE.jar - spring本身的包
spring-aspects-4.2.9.RELEASE.jar 针对aop联盟做出来的实现包,但这个实现包并不全部实现。
– 这两个包是额外的
aopalliance-1.0.jar 联盟包,其实就是aop规范
aspectjweaver-1.8.9.jar - 实现包
面向切面过程中,Spring AOP是遵循了AOP联盟的规范实现的,所以需要有AOP联盟的接口包
aopalliance-x.x.jar,接口包依赖aspectjweaver-x.x.x.jar导入约束
要导入aop的约束
<?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:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"> </bean> <bean id="logger" class="com.itheima.domain.logger"> </bean></beans>
- 让spring托管 业务逻辑类 和 增强类
<bean id="us" class="com.itheima.service.impl.UserServiceImpl" ></bean><bean id="logger" class="com.itheima.util.Logger" ></bean>
- 配置AOP
<!-- 下面的配置核心,就是把logger里面的log方法应用到us里面的save方法中 --> <!-- 开始aop的配置 --> <aop:config> <!-- 就是用于表示,要对哪一个方法进行增强。 其实就是定义一种规则,然后spring根据这种规则就能够找到对应的方法 后面将要对这些找到的方法进行增强 execution(* com.xyz.myapp.service.*.*(..)) execution : 固定写法,表示执行 第一个* : 表示任意返回值 com.xyz.myapp.service : 表示这个包 第二个* : 表示上面这个包的任意类 第三个* 表示上面找到的类的任意方法 (..) : 表示任意参数 spring根据这个表达式已经找到了具体对应的方法。 --> <aop:pointcut expression="execution(* com.itheima.service.impl.*.*(..))" id="savePointCut"/> <!-- 还缺少,把什么方法应用到上面找到的那些方法之上,去完成增强 连起来的意思就是: 把一个叫做logger的这个bean 里面的一个方法叫做 log 的方法,用到 一个叫做savePointCut 切入点找到 的那些方法上面去,执行前置增强 --> <aop:aspect ref="logger"> <!-- 定义前置增强 根据上面的表达式找到的切面,其实就是找到的那些方法,给他们应用前置增强, 把一个叫做log的方法用到他们前面去。 --> <aop:before method="log" pointcut-ref="savePointCut"/> </aop:aspect> </aop:config>
4. 增强
<!-- 配置aop --> <aop:config> <!-- 配置切入点 spring根据这个规则,找到具体的方法 xml方式不好控制具体哪一个方法 --> <aop:pointcut expression="execution(* com.itheima.service.impl.*.save(..))" id="pointCut01"/> <!-- 这个是对事务操作时,才有用 --> <!-- <aop:advisor advice-ref=""/> --> <aop:aspect ref="logger"> <!-- 前置增强 --> <!-- <aop:before method="log" pointcut-ref="pointCut01"/> --> <!-- 后置增强 --> <!-- <aop:after method="log" pointcut-ref="pointCut01"/> --> <!-- 环绕增强 --> //环绕异常也可以同时写上前置增强 和 后置增强,即为环绕异常 <!-- <aop:around method="around" pointcut-ref="pointCut01"/> --> <!-- 异常增强 --> <!-- <aop:after-throwing method="log" pointcut-ref="pointCut01"/> --> <!-- 最终增强 --> <aop:after-returning returning="result" method="log02" pointcut-ref="pointCut01"/> </aop:aspect>
- Day48-Spring-02
- Day48:Birthday
- day48,49,page140
- js实现回放拖拽轨迹-------Day48
- day48(4.28)软件测试书部分内容及一些面试题
- 达内学习日志Day48:注册与登录(二)
- Day48、模板特化、智能指针、模板的其他特性
- 【Day48】Redis监控主要指标及采集方法
- 《从零开始学Swift》学习笔记(Day48)——类型检查与转换
- 《从零开始学Swift》学习笔记(Day48)——类型检查与转换
- 34岁!100天!学会Java编程(Day45-Day48)—数据结构和基本算法
- python学习—Day48—celery多实例与定时任务
- 框架 day48 BOS项目练习2(base dao/action,登陆,消息提示框,菜单按钮,修改密码,登陆拦截器)
- 传智168期JavaEE day46~day48(by阿滔)笔记(2017年4月30日18:01:01)
- Spring 02
- Spring笔记02-Spring容器
- Spring 从零开始-02
- Spring-02-IOC容器
- 在Android中使用Java 8特性
- Scala sbt akka Eclipse 环境的配置
- 利用注解配置切面
- curses库的简单使用
- TL431常用电路
- Day48-Spring-02
- Struts2入门(6): Interceptor 拦截器体系
- POJ 2367 拓扑排序 解题报告
- 51Nod-1685-第K大区间2
- java基础——方法参数的值传递机制
- Java 发送邮箱简单实现
- HDU 6105 Gameia(树+博弈)
- Dubbo简单总结
- Python中的join函数用法