Spring框架
1.控制反转
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//getBean : 参数即为spring配置文件中bean的id .
Hello hello = (Hello) context.getBean("hello");
Hello hello = context.getBean("hello",Hello.class);
控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的
反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
2.依赖注入
依赖注入 : 就是利用set方法来进行注入的.要求被注入的属性 , 必须有set方法
依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .
注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 .
<bean id="OracleImpl" class="com.thebs.pojo.UserDaoOracleImpl"/>
<bean id="userDao" class="com.thebs.service.UserServiceImpl">
<!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写-->
<!--引用另外一个bean , 不是用value 而是用 ref-->
<property name="userDao" ref="OracleImpl"></property>
</bean>
常量注入、Bean注入、数组注入、List注入、Map注入
常量:<property name="name" value="小明"/>
bean:<property name="address" ref="addr"/>
数组、List、Set:类似
<property name="books">
<array>
<value>西游记</value>
<value>红楼梦</value>
<value>水浒传</value>
</array>
</property>
Map:
<property name="card">
<map>
<entry key="中国邮政" value="456456456465456"/>
<entry key="建设" value="1456682255511"/>
</map>
</property>
Null注入:<property name="wife"><null/></property>
Properties注入:
<property name="info">
<props>
<prop key="学号">20190604</prop>
<prop key="性别">男</prop>
<prop key="姓名">小明</prop>
</props>
</property>
拓展注入方式
①P命名空间注入 : 需要在头文件中假如约束文件
xmlns:p="http://www.springframework.org/schema/p"
可以直接注入属性的值
<bean id="user" class="com.kuang.pojo.User" p:name="狂神" p:age="18"/>
②C命名空间注入 : 需要在头文件中假如约束文件
xmlns:c="http://www.springframework.org/schema/c"
注入构造器参数
<bean id="user" class="com.kuang.pojo.User" c:name="狂神" c:age="18"/>
3.创建对象的方式
在执行getBean的时候, user已经创建好了
有参时的bean配置
①通过下标:
<constructor-arg index="0" value="kuangshen2"/>
②通过参数名:
<constructor-arg name="name" value="kuangshen2"/>
③通过参数类型:
<constructor-arg type="java.lang.String" value="kuangshen2"/>
4.Bean的配置
id 是bean的标识符,要唯一
name可以设置多个,用逗号,分号,空格隔开
不配置id和name时,可以根据applicationContext.getBean(.class)获取对象;
class是bean的全限定名=包名+类名
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
5.作用域
singleton:单例,默认
<bean name="hello" class="com.thebs.pojo.Hello" scope="singleton">
prototype:原型模式,每次从容器取都产生新对象
<bean name="hello" class="com.thebs.pojo.Hello" scope="prototype">
其余在web开发中使用
6.自动装配
byName:保证所有bean的id唯一,id值要与对象setXxx方法的值xxx一致;如果没有,就报空指针异常。
<bean id="user" class="com.kuang.pojo.User" autowire="byName">
byType:保证所有bean的class唯一,而且class要与注入的属性类型一致
<bean id="user" class="com.kuang.pojo.User" autowire="byType">
使用注解
jdk1.5开始支持注解,spring2.5开始全面支持注解。
①在spring配置文件中引入context文件头
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
②开启属性注解支持!
<context:annotation-config/>
@Autowired
是按类型自动转配的,不支持id匹配。
可将类中的set方法去掉,使用@Autowired注解
@Autowired
private Cat cat;
或写在set方法上
@Autowired
public void setCat(Cat cat){
this.cat = cat;
}
加上@Qualifier
则可以根据byName的方式自动装配
@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Resource
默认以byName方式进行装配,也可指定的name属性,不成功再按byType的方式自动装配。都不成功,则报异常。
@Resource(name = "dog1")
private Dog dog;
总结:@Autowired
与@Resource
异同:
同:
它们的作用相同都是用注解方式注入对象,都可以写在字段上,或写在setter方法上。
异:@Autowired
默认按类型装配(属于spring规范),@Resource
(属于J2EE规范),默认按照名称进行装配,找不到时按类型装配。需要注意的是,如果name属性一旦指定,就只会按照名称进行装配
7.使用注解开发
之前都是使用 bean 的标签进行bean注入,但是实际开发中,我们一般都会使用注解!
<!--指定注解扫描包-->
<context:component-scan base-package="com.thebs"/>
指定包中添加注解
@Component("user")
<!--相当于<bean id="user" class="当前注解的类"/>-->
@Component
的三个衍生注解
@Controller
:web层
@Service
:service层
@Repository
:dao层
属性注入
可不提供set方法,在属性名上添加@value(“值”)
提供了set方法,set方法上添加@value(“值”)
@Value("猪猪")
public void setName(String name) {
this.name = name;
}
自动装配
同上6
作用域
@Scope("prototype")
@Scope("singleton")
JavaConfig
@Component
//将这个类标注为Spring的一个组件,放到容器中!
@Component
public class Dog {
public String name = "dog";
}
@Configuration
//代表这是一个配置类
@Configuration //代表这是一个配置类
public class MyConfig {
@Bean //通过方法注册一个bean,这里的返回值是Bean的类型,方法名就是bean的id!
public Dog dog(){
return new Dog();
}
}
测试
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
Dog dog = (Dog) context.getBean("dog");
导入其他配置
@Import(MyConfig2.class)
总结
xml与注解比较:
XML可以适用任何场景 ,结构清晰,维护方便
注解不是自己提供的类使用不了,开发简单方便
xml与注解整合开发 :推荐最佳实践
xml管理Bean
注解完成属性注入
使用过程中,可以不用扫描,扫描是为了类上的注解
代理
①静态代理
//真实业务
UserServiceImpl userService = new UserServiceImpl();
//代理类
UserServiceProxy proxy = new UserServiceProxy();
//使用代理类实现日志功能!
proxy.setUserService(userService);
核心思想:我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想
【聊聊AOP:纵向开发,横向开发】
②动态代理
分为两类:
基于接口的动态代理——JDK动态代理
基于类的动态代理—cglib
一个动态代理 , 一般代理某一类业务
一个动态代理可以代理多个类,代理的是接口,但只可以代理一个接口
核心 :
InvocationHandler接口:每个代理实例都有一个调用处理程序,实现了此接口。内含invoke()方法
Proxy类:提供创建动态代理类的静态方法
创建抽象角色
创建真实角色
创建代理角色(实现了InvocationHandler接口)
①set方法;②getProxy()方法;③重写invoke方法
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
// proxy : 代理类
// method : 代理类的调用处理程序的方法对象.
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String s){
System.out.println("执行了"+s+"方法");
}
}
测试:
①创建真实对象
②创建代理对象的调用处理程序
③设置代理对象setTarget()
④动态生成代理类getProxy()
public class Test {
public static void main(String[] args) {
//真实对象
UserServiceImpl userService = new UserServiceImpl();
//代理对象的调用处理程序
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService); //设置要代理的对象
UserService proxy = (UserService)pih.getProxy(); //动态生成代理类!
proxy.delete();
}
}
AOP
AOP(Aspect Oriented Programming)意为:面向切面编程
①通过 Spring API 实现
execution表达式:
第一个*
任意访问修饰符的方法,第二个*
指定类下所有方法,(..)
表示任意参数
<!--注册bean-->
<bean id="userService" class="com.kuang.service.UserServiceImpl"/>
<bean id="log" class="com.kuang.log.Log"/>
<bean id="afterLog" class="com.kuang.log.AfterLog"/>
<!--aop的配置-->
<aop:config>
<!--切入点 expression:表达式匹配要执行的方法-->
<aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<!--执行环绕; advice-ref执行方法 . pointcut-ref切入点-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
②自定义类来实现Aop
<!--方式二:自定义类-->
<bean id="diy" class="com.thebs.diy.Diy"/>
<aop:config>
<!--自定义切面,ref要引入的类-->
<aop:aspect ref="diy">
<!--切入点-->
<aop:pointcut id="pointcut" expression="execution(* com.thebs.service.UserServiceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
③使用注解实现
@Aspect
public class Annotation {
@Before("execution(* com.thebs.service.UserServiceImpl.*(..))")
public void before(){}
<!--方式三:注解-->
<bean id="annotation" class="com.thebs.diy.Annotation"/>
<!--开启注解支持-->
<!--默认false是jdk,true是cglib-->
<aop:aspectj-autoproxy proxy-target-class="false"/>
Mybatis-Spring
使用 Maven 作为构建工具,仅需要在 pom.xml 中加入以下代码即可:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.2</version>
</dependency>
要和 Spring 一起使用 MyBatis,需要在 Spring 应用上下文中定义至少两样东西:一个 SqlSessionFactory
和至少一个数据源
dao层:整合Mybatis
①编写数据源
<!--DataSource:使用Spring的数据源替换Mybatis的配置 c3p0 druid-->
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
②sqlSessionFactory
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
</bean>
③sqlSessionTemplate
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
<constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>
需要给接口加实现类
①
public class UserMapperImpl implements UserMapper{
//原来我的的所有操作都使用sqlsession来执行,现在用sqlsessionTemplate
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> selectUser() {
return sqlSession.getMapper(UserMapper.class).selectUser();
}
}
②比起方式1 , 不需要管理SqlSessionTemplate
public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper {
@Override
public List<User> selectUser() {
return getSqlSession().getMapper(UserMapper.class).selectUser();
}
}
将实现类注入Spring
<bean id="userMapper" class="com.thebs.mapper.UserMapperImpl">
<property name="sqlSession" ref="sqlSession"/>
</bean>
<bean id="userMapper1" class="com.thebs.mapper.UserMapperImpl2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
用户调用Spring
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserMapper userMapper = context.getBean("userMapper1", UserMapper.class);
事务管理
确保数据的完整性和一致性
分为:
声明式事务:AOP。将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。
编程式事务:需要在代码中进行事务的管理
事务ACID原则:
原子性、一致性、隔离性、持久性
①配置声明式事务
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
②配置事务的通知
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!--给哪些方法配置事务-->
<!--配置事务的传播特性:new-->
<tx:attributes>
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete"/>
<tx:method name="update"/>
<tx:method name="query"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
③配置AOP
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.thebs.dao.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>
④测试