- IOC(DI) —— 注解
- 注解入门:
- 在applicationContext.xml中引入context约束
- 打开spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html中的xsd-configuration.html文件,搜索context schema,找到配置内容复制之,配置内容如下:
- 在applicationContext.xml中引入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">
</beans>
-
-
- 开启扫描组件:扫描配置的包名下的所有子孙包的注解
-
<!-- 开启扫描组件:扫描配置的包名下的所有子孙包的注解 --> <context:component-scan base-package="kong.spring.day03.dao"/>
-
-
- 创建UserDao接口
-
package kong.spring.day03.dao; public interface UserDao { public void save(); }
-
-
- 创建UserDao接口的实现类UserDaoImpl
-
package kong.spring.day03.dao; import org.springframework.stereotype.Component; // 使用注解的方式将对象交给Spring管理 // 相当于在xml中配置<bean name="userDao" class="kong.spring.day03.dao.UserDaoImpl"></bean> @Component(value="userDao") public class UserDaoImpl implements UserDao{ @Override public void save() { System.out.println("我是保存方法。。。save"); } }
-
-
- 创建测试类
-
package kong.spring.day03.test; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import kong.spring.day03.dao.UserDao; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class TestDemo { // 手动装配在UserDaoImpl中使用注解注入的userDao对象 @Resource(name="userDao") private UserDao userDao; @Test public void testIocAnnotation01() { // 测试能否成功调用使用注解注入的userDao对象的save方法 userDao.save(); } }
-
-
- 测试如果:在UserDaoImpl中使用注解注入的userDao对象能正常使用并调用其save方法
-
-
- 使用注解进行属性注入
- 使用注解Value("属性值")进行注入
- 可以在类属性上注入
- 也可以在set方法上注入
- 使用注解进行属性注入的类代码如下:
- 使用注解Value("属性值")进行注入
- 使用注解进行属性注入
package kong.spring.day03.dao; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; // 使用注解的方式将对象交给Spring管理 // 相当于在xml中配置<bean name="userDao" class="kong.spring.day03.dao.UserDaoImpl"></bean> @Component(value="userDao") public class UserDaoImpl implements UserDao{ // 没有set方法也能在属性上成功注入,但有set方法时,在属性上注入或set方法注入都可以,并不是“在有SET方法的时注解 @value("值") 必须添加在SET方法上”! @Value("NulluN_property") private String name; // 也可以在set方法上注入属性值 //@Value("NulluN_set") public void setName(String name) { this.name = name; } @Override public void save() { System.out.println("我是save保存方法;" + "name属性注入值为:" + name); } }
-
-
- 测试代码如下:
-
// 测试使用注解进行属性注入 @Test public void testIocDiAnnotation01() { // 通过调用userDao对象的save方法测试注解注入属性值是否成功 userDao.save(); }
-
-
- 测试结果:
-
-
- 根据MVC分层思想,由@Component衍生出来三种在其他类上的注解:
- @Controller:控制(web)层注解
- @Service:服务层注解
- @Repository:数据(持久/dao)层注解
- 测试在服务层使用@Service注解,同时测试使用@Autowired搭配@Qualifier或@Resource注解进行对象类型注入
- 创建UserService接口
- 根据MVC分层思想,由@Component衍生出来三种在其他类上的注解:
package kong.spring.day03.service; public interface UserService { public void save(); }
-
-
- 创建UserService接口的实现类UserSeviceImpl
-
package kong.spring.day03.service; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import kong.spring.day03.dao.UserDao; //服务层类注解 @Service("userService") public class UserSeviceImpl implements UserService {
// 使用@Autowired搭配@Qualifier进行对象类型注入
// 注意:可以只使用@Autowired来自动装配userDao对象;@Qualifier注解不能单独使用,单独使用会报错!
// 即@Qualifier需要和@Autowired搭配使用
//@Autowired
//@Qualifier(value = "userDao")
// 也可使用@Resource注解进行对象类型注入
@Resource(name = "userDao")
private UserDao userDao; @Override public void save() { userDao.save(); } }
-
-
- 测试服务层注解是否成功使用
-
// 测试使用@Service注解将服务层对象交给Spring管理 @Test public void testIocServiceAnnotation() { // 通过调用UserService对象的save方法,进而通过UserDao对象调用其save方法,测试UserDao的注解属性值注入是否成功 us.save(); }
-
-
- 测试结果:服务层注解成功将服务层对象交给Spring管理;同时,服务层使用使用@Autowired搭配@Qualifier注解成功将dao层的userDao对象注入到服务层,从而服务层对象成功调用dao层save方法
-
-
- 测试在dao层使用@Repository注解
- UserDaoImpl代码基本同上,在类上使用@Repository("userDao")注解将userDao对象交给Spring管理
- 测试代码:
- 测试在dao层使用@Repository注解
// 测试dao层使用@Repository注解 @Test public void testIocRepositoryDiAnnotation() { // 通过调用userDao对象的save方法测试用@Repository注解是否成功将对象交给Spring管理 UserDao.save(); }
-
-
- 测试结果:成功使用@Repository注解将userDao对象交给Spring管理
-
-
- Bean生命周期注解
-
创建实例后执行方法注解:@PostConstruct
-
销毁实例前执行方法注解:@PreDestroy
- 测试代码:
-
- Bean生命周期注解
@Resource(name = "userService") private UserService us; // 测试Bean生命周期注解 @Test public void testBeanLifeCycleAnnotation() { // 通过打印UserService对象来测试生命周期注解是否成功 System.out.println(us); }
-
-
- 测试结果:生命周期注解可以正常使用
-
-
- @Scope("值")注解,默认为单例,注解在类上
- 多例注解测试:
- @Scope("值")注解,默认为单例,注解在类上
-
-
- 测试类代码:
-
@Resource(name = "userService") private UserService us; @Resource(name = "userService") private UserService us2; // 测试@Scope多例注解 @Test public void testScopePrototypeAnnotation() { System.out.println(us); System.out.println(us2); System.out.println(us==us2); }
-
-
- 测试结果:
-
- XML与注解
- 区别:
- XML:结构清晰,维护方便
- 注解:开发方便
- XML与注解结合使用:
- XML管理Bean
- 属性注入用注解方式
- 演示代码中XML配置如下:
- 区别:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <!-- 开启扫描组件:扫描配置的包名下的所有子孙包的注解 --> <!-- 下面的开启扫描组件配置必须写,如果注释掉会报以下错误: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'kong.spring.day03.test.TestDemo': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userDao' is defined --> <!-- 由于Bean对象已在XML中配置交给Spring管理,故不用以下扫描配置来扫描相关包下用注解交给Spring管理的对象了! 也就是说可以将类中使用注解交给Spring管理的代码注释掉! --> <!-- <context:component-scan base-package="kong.spring.day03.dao"/> <context:component-scan base-package="kong.spring.day03.service"/> --> <!-- 当不需要使用扫描类,但需要使用注解方式实现属性注入时,用以下配置 --> <!-- 经测试:以下配置也可以不用!属性一样可以成功使用注解方式注入 --> <!-- <context:annotation-config/> --> <!-- XML与注解结合 --> <!-- XML管理Bean --> <bean name="userDao" class="kong.spring.day03.dao.UserDaoImpl"/> <bean name="userService" class="kong.spring.day03.service.UserServiceImpl"/> <bean name="carService" class="kong.spring.day03.service.CarServiceImpl"/> </beans>
-
-
- UserServiceImpl类代码如下:使用注解实现属性注入
-
package kong.spring.day03.service; import javax.annotation.Resource;import kong.spring.day03.dao.UserDao; public class UserServiceImpl implements UserService { @Resource(name = "userDao") private UserDao userDao; @Resource(name = "carService") private CarServiceImpl carService; @Override public void save() { carService.say(); userDao.save(); } }
-
-
- UserDaoImpl类代码如下:使用注解实现属性注入
-
package kong.spring.day03.dao; import org.springframework.beans.factory.annotation.Value; public class UserDaoImpl implements UserDao{ @Value("NulluN_property") private String name; public void setName(String name) { this.name = name; } @Override public void save() { System.out.println("我是save保存方法;" + "name属性注入值为:" + name); } }
-
-
- CarServiceImpl类代码如下:
-
package kong.spring.day03.service; public class CarServiceImpl { public void say() { System.out.println("我是擎天柱!"); } }
-
-
- 测试类代码如下:
-
// 手动装配在XML中配置的userService对象 @Resource(name = "userService") private UserService us; // 测试XML与注解结合:Bean在XML中配置,属性依赖注入使用注解在类中实现 @Test public void testXmlWithAnnotation() { us.save(); }
-
-
- 测试结果如下:XML与注解结合成功实现Bean交给Spring管理与属性注入
-
- Spring AOP:
- AOP:面向切面编程,是OOP的拓展延伸,解决OOP开发中遇到的问题
- AOP:横向抽取机制(代理机制)取代了OOP纵向继承
- Spring底层实现AOP原理:动态代理
- JDK的动态代理
- Cglib动态代理(第三方代理技术)
- Spring有自己实现AOP的方式,但被弃用,Spring目前实现AOP使用的是第三方的一个AOP框架,叫“AspectJ”
- AOP常用相关术语:
- 连接点(joinpoint):目标对象中,所有可以增强的方法,如下面例子中的CarInfoImpl类中的save方法
- 切入点(pointcut):目标对象中,已经增强的方法,如下面例子中CarInfoImpl类中的save方法被增强了
- 通知(advice):增强的代码,如下面例子中CarInfoProxy类中的checkSave方法
- 目标对象(target):被代理的对象,如下面例子中的CarInfoImpl类的对象
- 织入(weave):将通知应用到切入点的过程
- 代理(proxy):将通知织入到目标对象后形成代理对象
- 切面(aspect):通知+切入点
- AOP配置:
- 切面(通知)类和目标类都交给Spring管理
- 在applicationContext.xml中进行AOP配置前需要加入AOP约束规范,方法类同加入Beans和Context约束规范
- 下面是applicationContext.xml的配置代码:
<!-- AOP --> <!-- 目标类Bean配置 --> <bean name="carInfo" class="kong.spring.day03.aop.CarInfoImpl"/> <!-- 通知类配置 --> <bean name="carInfoProxy" class="kong.spring.day03.aop.CarInfoProxy"/> <!-- AOP配置 --> <aop:config> <!-- 配置切入点pointcut:配置需要增强的类中的哪些方法 --> <aop:pointcut expression="execution(* kong.spring.day03.aop.CarInfo.save(..))" id="carPointcut"/> <!-- 配置切面 --> <!-- 配置引用的切面类 --> <aop:aspect ref="carInfoProxy"> <!-- 在切入点carPointcut中配置前置通知,即执行目标类中方法前要调用以下的切面类中checkSave方法 --> <aop:before method="checkSave" pointcut-ref="carPointcut"/> </aop:aspect> </aop:config>
-
-
- 目标类的接口CarInfo
-
package kong.spring.day03.aop; public interface CarInfo { public void save(); }
-
-
- 目标类CarInfoImpl
-
package kong.spring.day03.aop; /** * AOP目标类,也可叫“被代理类”,这个类最好是实现接口,而不是直接定义!否则控制台会出现四行很烦人的警告信息! * @author NulluN * */ public class CarInfoImpl implements CarInfo{ public void save() { System.out.println("我买了一辆车,我要去浪。。。"); } }
-
-
- 切面类CarInfoProxy
-
package kong.spring.day03.aop; /** * AOP切面类,也叫“通知类” * @author NulluN * */ public class CarInfoProxy { public void checkSave() { System.out.println("我是增强的方法。。。"); } }
-
-
- 测试代码:
-
@Resource(name = "carInfo") private CarInfo carInfo; // 测试AOP前置通知 @Test public void testAopBeforeAdvice() { carInfo.save(); }
-
-
- 测试结果:AOP配置正常,目标类方法被成功增强,且是前置通知类型
-