一、IOC 注解开发
1. 注解和xml的配置对比
xml
优点 代码集中、容易查找、统一管理 缺点 代码量大
注解
优点 代码量少、方便、简单 缺点 查找比较麻烦、因为注解比较零散
2. IOC注解入门
- 导入jar包
spring-aop-xxx.jar
导入约束 context约束
<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">
在applicationContext.xml中打开注解的扫描开关
<!-- 打上注解扫描的开关,其实就是让spring去扫描对应的类上是否有注解,如果有,就解析注解 --> <context:component-scan base-package="com.itheima.service.impl"></context:component-scan>
在需要托管的具体类上面上注解,并且指定标识符
// Component :直译过来就是组件。 代码会分三层,每一层的具体类、 都称之为组件 @Component(value="us") //@Component : 光打上这个注解,就是告诉spring,要托管这个类。 还得让spring解析这个注解,以便得到us标识符 public class UserServiceImpl implements UserService {
3. 解释
xml :
注解扫描开关有两种写法: 但是建议使用第一种
<!-- 打上注解扫描的开关,其实就是让spring去扫描对应的类上是否有注解,如果有,就解析注解 -->
<context:component-scan base-package="com.itheima"></context:component-scan>
<!-- 还有另一种写法: 不推荐使用 这个只能扫描在xml里面登记的类-->
<!-- <context:annotation-config/> -->
注解:
@Component("us")
@Component : 等同于是告诉spring托管这个类
"us" : 等同于声明一个标识 类似bean里面的id
如果上面都不写就只是声明一个注解@Component 那么默认也会有一个标识符,这个标识符就是类名(但是第一个字母小写) 如: UserServiceImpl : id== userServiceImpl
4. 注解创建对象
注解创建多实例
默认创建的实例还是单例的 @Scope("prototype")
给类打上注解,以便让spring托管它,并且和标识符形成映射关系,都是靠@Component注解来实现
但是由于web项目采用分层的结构, controller 、 service 、 dao 层, spring为了迎合这种趋势,它也把注解稍微再细分了一下:@Component @Repository("userDao") //持久层 @Service("us") //业务逻辑层 @Controller("action") //控制层
指定初始化&销毁方法
@PostConstruct //用于定义指定方法为初始化方法 public void init(){ System.out.println("调用了UserServiceImpl的init方法~~"); } @PreDestroy //用于定义指定方法为销毁时调用的方法 public void destory(){ System.out.println("调用了UserServiceImpl的destroy方法~~"); }
5. DI的注解
注入普通数据:
普通数据其实可以不用注解的方式来注入,直接写上赋值即可。
@Value("北京")
private String address;
注入对象数据
早期的xml注入:
<!--1. 这行代码就是让spring托管这个类,然后给这个类打上一个标识符
在这个类上面打上注解
-->
<bean id="ud" class="com.itheima.dao.impl.UserDaoImpl"></bean>
<bean id="us" class="com.itheima.service.impl.UserServiceImpl">
<!-- 2. 把ud对应的类实例给注入到userDao中 -->
<property name="userDao" ref="ud"></property>
</bean>
注解的注入
1. 在需要注入进来的那个类打上注解,让spring托管它
@Repository("ud")
public class UserDaoImpl implements UserDao{
2. 在成员属性上使用注解来注入对象
@Resource(name="ud") //根据给定的标识符找到具体的类 name="" ====> ref=""
//@Autowired //自动找到这个接口的实现类然后注入进来
private UserDao userDao ;
如果只有一种实现的情况,又懒得写太多,就可以直接使用 @Autowired 。 但是如果存在多种实现,又想指定具体的某一个实现,那么请使用 @Resource(name=”标识符”)
6. xml 和 注解 混合使用
使用xml来托管bean , 使用 注解来注入属性
二、 Spring测试
导入jar包
spring-test-xxx.jar
在测试类上面打上注解,指定运行环境以及xml文件所在
给成员打上注解,注入对象即可
//指定当前测试使用的运行环境, 除了兼备以前junit的运行环境之外 还会解析xml 创建工厂 @RunWith(SpringJUnit4ClassRunner.class) //指定以下xml文件在哪里 @ContextConfiguration("classpath:applicationContext.xml") public class MainTest { //只有在测试类里面 用到的那些注解,不用打开注解扫描开关,但是在service\dao\action里面有注解的话,那么请打开注解扫描开关。 @Autowired private UserService userService; @Test public void testSave(){ userService.save(); } }
三、AOP
- 什么是AOP?
AOP(Aspect Oriented Programming,面向切面编程),可以说是OOP(Object Oriented Programing,面向对象编程)的补充和完善。
具体应用在: 不想改动源码的前提下还想对这份功能进行扩展和增强。
1. AOP的底层原理
虽然已经知道了AOP就是用来做增强、扩展的。 可选的方案无非就是装饰者模式 、 代理模式(静态代理、 动态代理) 。 spring的aop采用了动态代理的手法。两种动态代理实现
- 基于JDK的动态代理
真实类实现具体的接口,做出来接口的又一个实现类作为代理类
@Test
public void testJdkProxy(){
//1. 创建真实对象
final UserService userService = new UserServiceImpl();
//2. 创建代理
UserService proxyObj = (UserService) Proxy.newProxyInstance(
userService.getClass().getClassLoader(), //类加载器。 一般这里就采用真实类用什么类加载器,这里就写什么类加载器
userService.getClass().getInterfaces(), //真实类实现什么接口,这里就写什么接口。也就是表示了代理类实现什么接口
new InvocationHandler() { //用于处理代理对象调用方法的回调
/*
* 外面使用代理对象调用方法,这个invoke方法就会执行。(non-Javadoc)
* method : 外面具体的方法引用。
* args :外面调用的方法参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//Logger.log();
if(method.getName().equals("save")){
System.out.println("执行了输出日志的功能");
}
//采用反射的手法调用真实对象中的方法
return method.invoke(userService, args);
}
});
//3. 使用代理对象调用方法
proxyObj .save(); // 外面调用的是代理对象的方法,背后真正干活是真实对象, 也就是userService.save();
}
- 基于Cglib动态代理
真实类没有实现任何接口, 做出来真实类的又一个子类作为代理类
@Test
public void testCglibProxy(){
//1. 创建真实对象
final ProductService productService = new ProductService();
//2. 创建代理对象enhancer 不是代理对象。 只是要借助它来创建代理对象
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("输出日志~");
return arg1.invoke(productService, arg2);
}
});
//创建出来代理对象
ProductService proxyObj = (ProductService) enhancer.create();
proxyObj.save();
}
2. AOP术语
3. AOP入门
- 导包
四、总结
1. IOC注解 【重点】
1. 导入jar包
spring-aop-xxx.jar
2. 导入约束
context约束
3. 打开注解扫描开关
<context:component-scan base-package="">
4. 在类上面打上注解
@Component
@Repository
@Service
@Controller
5. DI 注入 【重点】
@Autowired
@Resource(name="")
2. Spring测试
1. 导入spring-test-xx.jar
2. 添加注解
@Runwith(SpringJunit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
测试类里面的注解不用打开扫描开关
3. AOP
1. aop是什么,有什么用
面向切面编程,在不改动源码的前提下对功能进行扩展、增强
2. aop的底层
动态代理 : jdk + cglib
3. aop入门【重点】
a. 导入jar包 : 4个
aop联盟包 、 aspectJ实现包 spring-aop-xxx.jar spring -aspect-xx.jar
b. 导入约束
aop约束
c. 托管业务逻辑类和 扩展的功能类
d. 配置aop
<aop:config>
<aop:aspect ref="logger">
<!-- 前置增强 -->
<aop:before method="log" pointcut="execution(* com.itheima.service.impl.*.*(..))"/>
</aop:aspect>
</aop:config>