Spring
IOC的Bean的管理
IOC的底层原理
- 使用工厂模式和反射,通过构造方法和set方法来注入属性;
- DI依赖注入使得对象之间的关系得到了解耦,降低了程序的耦合性;
1.xml注入
<util:list id="list">
<value>撒哈拉沙漠</value>
<value>月亮与九便士</value>
<value>小王子</value>
</util:list>
<bean id="person" class="com.Person">
<property name="user" ref="user"/>
<property name="name" value="黄"/>
<property name="list" ref="list"/>
</bean>
<bean id="user" class="com.User"/>
<bean id="myBean" class="com.myBean"/>
2.Spring有两种类型的Bean,一种普通Bean和一种工厂bean(FactoryBean)
-
普通Bean在配置文件中定义的返回类型就是Bean类型;
-
工厂Bean在配置文件中定义的返回类型和Bean类型可以不一样;
-
创建类,实现FactoryBean接口;
-
实现接口中的方法,定义返回的Bean的类型;
import org.springframework.beans.factory.FactoryBean; public class myBean implements FactoryBean<User> { public User getObject() throws Exception { return new User(); } public Class<?> getObjectType() { return User.class; } public boolean isSingleton() { return true; } }
-
3.Bean的作用域
- 在spring中Bean默认是单例对象;
- 在Bean的配置中scope有两个选择:singleton和prototype;
- 设置是singleton时,在spring加载配置文件的时候就会创建单例对象;
- 设置是prototype时,在getBean时创建一个多实例对象;
4.Bean的生命周期
- 通过构造方法来创建Bean实例;(一般为无参构造)
- 给Bean的属性设置值和注入对其它Bean的引用;(通过set方法)
- 把Bean的实例传递给Bean的后置处理器;BeanPostProcessor接口的实现
- 调用Bean的初始化方法;(需要自己配置初始化方法)
- 把Bean的实例传递给Bean的后置处理器;BeanPostProcessor接口的实现
- Bean可以被使用了;
- 当容器被关闭时,调用Bean的销毁方法;(需要自己配置销毁方法)
5.XML引入外部对象
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="name" value="${name}"/>
<property name="password" value="${password}"/>
<property name="driver" value="${driverClass}"/>
<property name="url" value="${url}"/>
</bean>
<context:property-placeholder location="jdbc.properties"/> <--导入配置文件-->
使用注解管理Bean
简化xml配置
1.Spring针对Bean管理中创建对象的注解
-
@Component
-
@Repository
-
@Service
-
@Controller
针对不同层,使用不同的注解,但它们的作用都是一样的;
2.基于注解实现属性的注入
- @Autowired;根据类型
- @Qualifier;根据名称
- @Resource;可以根据类型或名称
- @Value;注入普通类型
3.完全注解开发
@Configuration//申明这是个配置类
@ComponentScan(basePackages = {"annotation"})//指定Bean的扫描的包
public class Configuration1 {
}
AOP
1.概念:原理就是动态代理
- 利用AOP可以对业务逻辑的各个部分进行隔离,从而使的业务逻辑的各部分的耦合度降低,提高程序的可重用性,同时提高开发效率;
- 在不修改原有业务代码的基础上,添加新的功能,比喻日志,事务;
2.AOP的底层原理
-
动态代理;
- 有借口:JDK的动态代理;
- 无接口:CGLIB动态;
3.术语
-
连接点
- 类中可以被增强的方法;
-
切入点
- 实际被增强的方法;
-
通知(增强)
- 实际被增强的逻辑部分被称为通知;
- 通知的类型;
- 前置通知
- 后置通知
- 环绕通知
- 异常通知
- 最终通知
-
切面
- 是一个动作:把通知应用到切入点的过程;
4.spring的aop操作
-
aop简介;
- spring是基于aspectj来实现aop操作的;
- aspectj不是spring的组成部分,是一个独立的aop框架,一般吧aspectj和spring框架一起使用;
-
使用配置xml或注解;
-
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect public class UserProxy { //相同切入点的抽取 @Pointcut(value = "execution(* aopannotation.User.*(..))")//aop表达式 public void point(){ } @Before(value = "point()")//用这个来代替相同的aop表达式 public void before(){ System.out.println("Before前置通知"); } @After(value = "point()") public void after(){ System.out.println("After最终通知"); } @AfterReturning(value = "execution(* aopannotation.User.*(..))") public void return1(){ System.out.println("AfterReturning后置通知"); } @AfterThrowing(value = "execution(* aopannotation.User.*(..))") public void exception(){ System.out.println("AfterThrowing异常通知"); } @Around(value = "execution(* aopannotation.User.*(..))") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("Around环绕通知前"); proceedingJoinPoint.proceed(); System.out.println("Around环绕通知后"); return proceedingJoinPoint; } } Around环绕通知前 Before前置通知 my name is 123 AfterReturning后置通知 After最终通知 Around环绕通知后
-
-
使用@Order()设置优先级,来使得对相同方法的不同增强类进行增强;
-
@Component @Aspect @Order(1)//数字越小,优先级越高 Around环绕通知前Order(1) Before前置通知Order(1) Around环绕通知前Order(3) Before前置通知Order(3) my name is 123 AfterReturning后置通知Order(3) After最终通知Order(3) Around环绕通知后Order(3) AfterReturning后置通知Order(1) After最终通知Order(1) Around环绕通知后Order(1)
-
-
完全使用注解
@Configuration @ComponentScan(basePackages = {"aopannotation"}) @EnableAspectJAutoProxy(proxyTargetClass = true)//开启aop //相当于下面的内容 <context:component-scan base-package="aopannotation"/> <aop:aspectj-autoproxy/>//开启aop
JDBCTemplate
-
使用jdbctemplate操作数据库
@Repository public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; public void add(User user){ String sql="insert into user values(?,?,?)"; int update = jdbcTemplate.update(sql, user.getId(), user.getName(), user.getPwd()); System.out.println(update); } public void update(@NotNull User user) { String sql="update user set user.name=?,user.pwd=? where id=?;"; int update = jdbcTemplate.update(sql, user.getName(), user.getPwd(), user.getId()); System.out.println(update); } public void delete(int id) { String sql="delete from user where id=?;"; int update = jdbcTemplate.update(sql, id); System.out.println(update); } public int count(){ String sql="select count(*) from user"; return jdbcTemplate.queryForObject(sql, Integer.class); } public User queryById(int id){ String sql="select * from user where id=?"; return jdbcTemplate.queryForObject(sql, new BeanPropertyRowMapper<User>(User.class), id); } public List<User> findAll(){ String sql="select * from user where id between 12 and 88"; return jdbcTemplate.query(sql, new BeanPropertyRowMapper<User>(User.class)); } public void batchAddUser(List<Object[]> list){ String sql="insert into user values(?,?,?)"; int[] ints = jdbcTemplate.batchUpdate(sql, list); System.out.println(Arrays.toString(ints)); } public void batchUpdateUser(List<Object[]> list){ String sql="update user set name=?,pwd=? where id=?;"; int[] ints = jdbcTemplate.batchUpdate(sql, list); System.out.println(Arrays.toString(ints)); } public void batchDeleteUser(List<Object[]> list){ String sql="delete from user where id=?;"; int[] ints = jdbcTemplate.batchUpdate(sql, list); System.out.println(Arrays.toString(ints)); } } //需要配置jdbcTemplate <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean>
Transaction
-
使用事务:注解或xml;
-
一般把事务添加到三层结构中的service层中;
- 两种方式:编程式和声明式;
- 声明式事务管理,底层使用的AOP原理;
<bean id="transactionManage" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:annotation-driven transaction-manager="transactionManage"/>
-
事务的传播机制;
- required:
- required_new:
- supports:
- not_supports:
- mandatory:
- never:
- nested:
-
隔离界别:1.默认数据库的级别
2.数据库的四种默认级别
-
超时时间:timeout
-
readonly:是否只读,默认为false;
-
rollbackfor:设置哪些异常进行回滚;
-
norollbackfor:设置哪些异常不进行回滚;
Spring5的新功能
1、整合日志框架
-
整合Log4j2日志;
-
log4j-api;log4j-core;log4j-slf4j-impl;slf4j-api;
-
固定的配置xml文件;
-
<?xm1 version=1.0" encoding="UTE-8"?> <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --> <!--Configuration后面的status用于设置1og4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部 各种详细输出--> <configuration status="OFF"> <!--先定义所有的appender--> <appenders> <!--输出日志信息到控制台--> <console name="Console" target="SYSTEM_OUT"> <!--控制日志输出的格式--> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/> </console> </appenders> <!--然后定义logger,只有定义了logger并引入的appender, appender才 会生效- -> <!-root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出--> <loggers> <root level="info"> <appender-ref ref="Console"/> </root> </loggers> </configuration>
-
Logger logger = LoggerFactory.getLogger(T2.class); //使用logger来手动输出日志信息
2、@Nullable注解
- @Nullable注解可使用在方法,属性,方法参数上,表示方法返回可为空,属性可为空,参数可为空;
3、函数式注册对象
-
public void teat2() { //使用函数式风格来注册Bean GenericApplicationContext context = new GenericApplicationContext(); context.refresh(); context.registerBean("user1",User.class, 1,"123","18"); User user1 = (User) context.getBean("user1"); User user2 = (User) context.getBean("user1"); System.out.println(user1==user2); System.out.println(user1); } true User{id=1, name='123', pwd='18'}
4、整合JUnit5单元测试
-
//使用的是Junit4 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = txConfig.class) //使用的是Junit5 @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = {txConfig.class}) //把上面的两个注解合并为下面一个 @SpringJUnitConfig(value = {txConfig.class})