# myhomework_002 **Repository Path**: ea-creator/myhomework_002 ## Basic Information - **Project Name**: myhomework_002 - **Description**: IOC,AOP模块HomeWork - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-01-01 - **Last Updated**: 2021-01-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 一、编程题 学员自定义@Service、@Autowired、@Transactional注解类,完成基于注解的IOC容器(Bean对象创建及依赖注入维护)和声明式事务控制,写到转账工程中,并且可以实现转账成功和转账异常时事务回滚 注意考虑以下情况: 1)注解有无value属性值【@service(value="") @Repository(value="")】 2)service层是否实现接口的情况【jdk还是cglib】 二、作业资料说明: 1、提供资料:代码工程、验证及讲解视频、SQL脚本。 2、讲解内容包含:题目分析、实现思路、代码讲解。 3、效果视频验证 1)实现转账成功和转账异常时事务回滚。 2)展示和讲解自定义@Service、@Autowired、@Transactional注解类。 ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー 1.弄清楚Spring里面的@Service,@Autowired,@Transactional的功能以及是如何被处理的。 1.1.关于@Service (1)功能约定: @Service 与 @Controller, @Repository 功能一样都是 @Component 注解的别名, 是用来向Spring IOC容器中注入对象用的注解。 (2)@Service 与 xml配置的对应关系: 例如: @Service("transferService") public class TransferServiceImpl 等同于xml配置时候的下面的定义 (3)@Service 缺省配置的时候,以对那个的类的首字母小写作为ID,将对应的类添加到Spring IOC 容器中 @Service 注解其实就是一种约定,告诉框架需要将含有此注解的类对应的对象添加到Spring IOC 容器中 1.2.关于@Autowired (1)功能约定: - @Autowired 告诉框架它对应的属性需要自动从IOC容器中找到同一类型的对象注入到此属性上 (2)@Autowired 与 xml配置的对应关系: 例如: @Autowired @Qualifier("accountDao") private AccountDao accountDao; 等同于xml配置时候的下面的定义,不同的是xml配置的需要对应的set+ name方法,而@Autowired不需要set+ name方法 (3)@Autowired 采取的策略为按照类型注⼊。 当⼀个类型有多个bean值的时候,会造成⽆法选择具体注⼊哪⼀个的情况,这个时候我们需要配合着@Qualifier使⽤。 1.3.@Transactional功能 (1)功能约定: - 加了 @Transactional 注解的类或者方法,框架会对其使用事务增强。 本次作业我实现对类上面添加 @Transactional 的方法进行事务增强。 2.注意考虑以下情况: (1)注解有无value属性值【@service(value="") @Repository(value="")】 ->如果对应注解的value为""则以类的首字母小写为ID放到IOC容器中 (2)service层是否实现接口的情况【jdk还是cglib】 在Spring中: ->如果实现接口则采用jdk代理 ->如果没有实现接口则使用cglib代理 我自己的本次作业中: ->通过自定义@Transactional中的type来指定使用何种代理 3.解题思路: 3.1.因为需要使用注解方式,所以首先要会使用自定义注解(TestAnnotation工程学习使用类注解,字段注解,方法注解) 3.2.实现的思想与老师教程里面的com.lagou.edu.factory.BeanFactory的思想类似。 只不过之前是使用dom4j读取解析xml,然后先将解析到的bean通过反射技术实列化后放到IOC容器, 然后将解析到的property找到ref对应的bean,然后调用set+name方法将属性注入到对象中。 3.3.注解方式的话实现的思路 (1)现根据配置类拿到要检索的包名,然后检索该包下面的所有的类 (2)先找 @Service(@Component, @Repository)对应的类,通过反射技术将其保存到IoC容器中 ->如果对应注解的value为""则以类的首字母小写为ID放到IOC容器中 (3) 找到带有 @Autowired 注解的类,从容器中找到与注解的ID相同的对象注入到该对象中 (4) 找到带有 @Transactional 注解的类,从容器中找到与其ID相同的代理 4.代码构成: 4.1.TestAnnotation工程 (学习自定义注解时的成果) | pom.xml | TestAnnotation.iml | +---src | +---main | | +---java | | | \---com | | | \---zbz | | | \---annotation | | | \---pattern3 | | | FiledAnnotation.java <- <1>.作用在属性上注解 | | | MethodAnnotation.java <- <2>.作用在方法上注解 | | | TypeAnnotation.java <- <3>.作用在类上注解 | | | Worker.java <- <4>.使用自定义注解 | | | | | \---resources | \---test | \---java | TestMain.java <- <5>.测试自定义注解 4.2.lagou-transfer-homework(本次的作业工程) | lagou-transfer-homework.iml | pom.xml | ReadMe.txt | DDL_DML.sql <- SQL的DDL,DML语句 | | +---src | +---main | | +---java | | | \---com | | | \---lagou | | | \---edu | | | | SpringConfig.java <- 自定义配置类(@ComponentScan我以类的全限定名的形式配置为检索对象,@Value未实现,以变量赋值代替,@Bean注解的方法返回的对象注入IoC容器 | | | | | | | +---dao | | | | | AccountDao.java <- 没动,还给老师:) | | | | | | | | | \---impl | | | | JdbcAccountDaoImpl.java <- @Repository("accountDao"),@Autowired改为导入我自定义的注解 | | | | | | | +---factory | | | | BeanFactory.java <- 没动,还给老师:) | | | | ProxyFactory.java <- @Component(""),@Autowire改为导入我自定义的注解 | | | | | | | +---myspringframework | | | | +---beans | | | | | \---factory | | | | | \---annotation | | | | | Autowired.java <- 自定义@Autowired注解 | | | | | PropertySource.java <- 自定义@PropertySource注解,本次为为此具体实现属性相关的注入 | | | | | Value.java <- 自定义@Value注解,本此时间关系没有作为实现对象 | | | | | | | | | +---context | | | | | \---annotation | | | | | Bean.java <- 自定义@Bean注解,本次用其对配置类里面的createDataSource()方法进行解析 | | | | | ComponentScan.java <- 自定义@ComponentScan注解,本次降低一下实现难度,将需要IOC容器生成的对象的类以数组的形式定义配置 | | | | | MyAnnotationConfigApplicationContext.java | | | | | <- 本次作业的核心代码, | | | | | 1.先解析配置类: | | | | | - 1.1.通过parseComponentScan(Class clzz)方法,扫描类上的 @ComponentScan 注解,获取需要处理的类的一览 | | | | | - 1.2.通过parsePropertySource(Class clzz)方法,扫描类上的 @PropertySource 注解,获取需要属性配置文件(对象外,未作深入处理) | | | | | - 1.3.通过parseBean(Class clzz) 方法,扫描类上的@Bean注解,执行对应方法将对象注入IOC容器 | | | | | 2.通过parseComponent() 方法,将扫描到的类进行注解解析@Component,@Service,@Repository对应的类实例化放入一级缓存 | | | | | 3.通过parseAutowiredProperty() 方法,自动装配 @Autowired 注解属性。如果 @Autowired 注解所在的类没有被实例化先实例化存入3级缓存, | | | | | 之后查找 @Autowired 对应的对象进行注入,注入好的对象按照3-2-1的顺序提升缓存的级别。如果原来对象储存在3级缓存中就保存到2级里面,从原来3级里面删除。 | | | | | 依次类推。 | | | | | 4.通过parseTransactional()方法对包含 @Transactional 注解的类进行事务增强, | | | | | 先判断一下有此注解的类是否被实例化,如果没有实例化则进行实例化放入3级缓存。 | | | | | 对于注解 @Transactional 我加了一个代理属性type,默认使用JDBC动态代理, | | | | | 如果@Transactional注解中定义为CGLIB则使用CGLIB动态代理增强。 | | | | | 增强之后的对象也进行缓存的级别提升。 | | | | | | | | | | | | | | +---stereotype | | | | | Component.java <- 自定义@Component注解 | | | | | Configuration.java <- 自定义@Configuration注解 | | | | | Repository.java <- 自定义@Repository注解 | | | | | Service.java <- 自定义@Service注解 | | | | | | | | | \---transaction | | | | \---annotation | | | | Transactional.java <- 自定义@Transactional注解 | | | | | | | +---pojo | | | | Account.java <- 没动,还给老师:) | | | | Result.java <- 没动,还给老师:) | | | | | | | +---service | | | | | TransferService.java <- 没动,还给老师:) | | | | | | | | | \---impl | | | | TransferServiceImpl.java <- @Service("transferService"),@Transactional(type=Transactional.ProxyType.CGLIB) 使用自定义注解 | | | | | | | +---servlet | | | | TransferServlet.java <- init() 方法中使用自定义的MyAnnotationConfigApplicationContext,然后自定义的IOC容器中获取transferService对象 | | | | | | | \---utils | | | ConnectionUtils.java <- @Component("connectionUtils"), @Autowired 使用自定义注解 | | | JsonUtils.java <- 没动,还给老师:) | | | StringTools.java <- 写的一个工具类,处理注入IOC时的对象的Id时首字母小写 | | | TransactionManager.java <- @Component("transactionManager"), @Autowired 使用自定义注解 | | | | | +---resources | | | jdbc.properties <- 没动,还给老师:) | | | | | \---webapp | | | index.html <- 没动,还给老师:) | | | | | +---js | | | jquery-3.4.1.min.js <- 没动,还给老师:) | | | | | \---WEB-INF | | web.xml <- 将原来的正对Spring的配置删除了 | | | \---test | \---java | IoCTest.java <- TestOriginalIOC() 测试对象是否被注入到容器中,testString()测试了一下工具类