1.框架封装了很多技术,但缺少业务逻辑,方便开发使用。
2.MVC框架:struts1,struts2,SpringMVC
持久层框架:hibernate,mybatis
整合型框架:spring
3.MVC:控制层接受到客户端请求,调用模型层生成业务数据,传递给视图层,将最终的业务数据和视图响应给客户端做展示
4.当通过类型来获取对象是可以不设置ID
ApplicationContext ac= new ClassPathXmlApplicationContext("beans.xml");
ac.getBean(); //如果参数为类型则不用设置ID,但是如果当Bean配置文件中出现多个相同对象会发生错误,所以一般采用
ac.getBean('ID' , '类.class')
5.spring创建对象依赖于无参构造,给属性赋值依赖于get,set方法。
6.给bean的属性赋值
6.1properties标签赋值,通过get,set注入(常用)
<bean id="person" class="com.spring01.Person" >
<property name="name" value="liyong"></property>
<property name="age" value="18"></property>
</bean>
6.2构造函数
<bean id="person" class="com.spring01.Person" >
<constructor-arg value=""/>
<constructor-arg value=""/>
</bean>
//自动匹配参数
<bean id="person" class="com.spring01.Person" >
<constructor-arg index="0" type="java.lang.Double" value=""/>
<constructor-arg index="1" value=""/>
</bean>
//可以通过index来制定参数,type指定类型
6.3P命名空间
xmlns:p="http://www.springframework.org/schema/p"
<bean id = "" class = "" p:name = "" p:age = "";></bean>
6.4注入时可以用的值
6.4.1字面量(基本数据类型,基本类型包装类,String)通过value=“值”即可,ref引用对象
<bean id="person" class="com.spring01.Person">
<property name="age" value="2"></property>
<property name="name" value="f"></property>
<property name="t" ref="teacher"></property>
</bean>
<bean id="teacher" class="com.spring01.Teacher">
<property name="age" value="2"></property>
<property name="tid" value="f"></property>
</bean>
6.4.2级联赋值
<bean id="person" class="com.spring01.Person">
<property name="age" value="2"></property>
<property name="name" value="f"></property>
<property name="t" ref="teacher"></property>
<property name="t.age" value="teacher"></property>
</bean>
<bean id="teacher" class="com.spring01.Teacher">
</bean>
6.4.3内部bean
<bean id="person" class="com.spring01.Person">
<property name="age" value="2"></property>
<property name="name" value="f"></property>
<property name="t" >//t属性为对象类型
<bean id=""></bean> //只属于该bean,其他bean访问不到此bean
</property>
</bean>
6.4.2集合属性赋值
案例1
private Integer age;
private String name;
private Teacher t;
private List<String> list;
<bean id="person" class="com.spring01.Person">
<property name="age" value="2"></property>
<property name="name" value="f"></property>
<property name="t" ref="teacher"></property>
<property name="list">
<list>
<value>a</value>
<value>b</value>
<value>c</value>
</list>
</property>
</bean>
案例2
private String tid;
private int age;
private List<Person> personList;
<bean id="teacher" class="com.spring01.Teacher">
<property name="age" value="2"></property>
<property name="tid" value="f"></property>
<property name="personList">
<list>//数组<array></array>,<set></set>用法与list类似
<ref bean="person"/>//此处也可以防止内部bean标签
<ref bean="person1"/>
<ref bean="person2"/>
<ref bean="person3"/>
</list>
</property>
</bean>
案例3map
<bean id="teacher" class="com.spring01.Teacher">
<property name="age" value="2"></property>
<property name="tid" value="f"></property>
<property name="map">
<map>
<entry>
<key>
<value></value>
</key>
<value>gfdskg<value/>
</entry>
</map>
</property>
</bean>
案例四
<bean id="person" class="com.spring01.Person">
<property name="age" value="2"></property>
<property name="name" value="f"></property>
<property name="t" ref="teacher"></property>
<property name="list">
<ref bean="persons"></ref>//注意类型问题
</property>
</bean>
<bean id = "persons">
<utl:list> //<utl:map>等标签用法类似
<ref bean="person1"/>
<ref bean="person2"/>
<ref bean="person3"/>
//引入空间:xmlns:utl="http://www.springframework.org/schema/util"
</utl:list>
</bean>
7.BeanFactory
spring创建对象采用的是工厂模式,spring中有两种Bean工厂Bean和普通Bean,继承了BeanFactory就为工厂Bean.配置工厂bean创建的对象为工厂里生成的对象而非工厂对象本身。
案例
public class Car {
private Integer size;
private Integer price;
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
@Override
public String toString() {
return "Car{" +
"size=" + size +
", price=" + price +
'}';
}
}
工厂类
public class MyFactory implements FactoryBean<Car> {
public Car getObject() throws Exception {
Car car = new Car();
car.setPrice(100);
car.setSize(100);
return car;
}
public Class<?> getObjectType() {
return Car.class;
}
public boolean isSingleton() {
return false;
}
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Object obj= (Object)context.getBean("carFactory");
System.out.println(obj);
}
Car{size=100, price=100}
8.bean的作用域
单例容器初始化时就会创建好
<bean id="person" class="com.spring01.Person" scope="singleton">
<property name="name" value="jf"></property>
<property name="age" value="33"></property>
</bean>
原型模式
每次执行都创建一个
<bean id="person" class="com.spring01.Person" scope="prototype">
<property name="name" value="jf"></property>
<property name="age" value="33"></property>
</bean>
9.bean的生命周期
9.1创建
9.2依赖注入
9.3初始化
9.4使用
9.5销毁
9.6bean后置处理器,设置后对sprig管理的每一个对象都有效果。
<bean id="person" class="com.spring01.Person" scope="prototype" init-method="ini" destroy-method="des">//调用初始化和销毁方法
<property name="name" value="jf"></property>
<property name="age" value="33"></property>
</bean>
后置处理
public class AfterHandler implements BeanPostProcessor {
//返回的object是处理后新的bean
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//业务逻辑
return null;
}
//返回的object是处理后新的bean
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//业务逻辑
return null;
}
}
同样需要在bean中配置
<bean class="com.beanzone.AfterHandler"></bean>
10引用外部属性文件
案例druid
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
destroy-method="close" lazy-init="false">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialSize" value="1" />
<property name="maxActive" value="50" />
<property name="maxWait" value="30000" />
<property name="filters" value="stat,wall" />
<property name="timeBetweenEvictionRunsMillis" value="3000" />
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="validationQuery" value="SELECT 'x'" />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize"
value="20" />
</bean>
属性值可以写死,也可以读取properties ${}文件配置
新建properties文件,并注入bean
jdbc.driver=****
………………等等配置
将properties文件交给bean管理后便可以通过${进行赋值}
写法一
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location" value="db.properties"></property>
</bean>
写法二
<context:property-placeholder location="db.properties"/>
11.spring自动装配(针对非字面量属性)
11.1byName通过bean的ID获取对象
private Integer age;
private String name;
private Teacher t;
<bean id="person" class="com.byName.Person" autowire="byName">
<property name="name" value="jf"></property>
<property name="age" value="23"></property>
</bean>
<bean id="t" class="com.byName.Teacher" >
<property name="tid" value="jf"></property>//bean的ID要和属性名字一样否则找不到
<property name="age" value="23"></property>
</bean>
11.2byTye通过类型装配
通过类型装配只要有相对应的类型赋值就能完成装配,可以赋值给父类和实现的接口,但如果有多个则要报错找不到唯一值
private Integer age;
private String name;
private Teacher t;
<bean id="person" class="com.byName.Person" autowire="byType">
<property name="name" value="jf"></property>
<property name="age" value="23"></property>
</bean>
<bean id="ttt" class="com.byName.Teacher" >
<property name="tid" value="jf"></property>
<property name="age" value="23"></property>
</bean>
11.3autowire:根据某种策略自动为非字面量属性赋值
通过以上情况赋值存在的问题:
会作用于所有非自面量因此一般不用这种写法。
12.通过注解配置(不能加到抽象类和接口上,不能实例化对象)
12.1@Component:普通组件
@Repository:持久化组件(持久层:数据访问层)
@Service:业务逻辑层组件
@Controller (value=“”“”)或只设置一个属性时Controller(" "):控制组件(在mvc中有区别,交给serverlet容器管理,扫描为控制组件),如果设置了value的值则spring容器中beanID为此值
区别:作用一样但是名字不同(将类交给spring管理),只是标识代码的逻辑完成什么工作。
12.2加上注解后要进行扫描,将注解类作为spring的组件来加载,即spring中管理的bean
//需要扫描的包名建议写的精确一些,避免扫描不需要交给spring管理的类
<context:component-scan base-package="com.zhujie"></context:component-scan>
//加入spring后默认以类名首字母小写为ID
12.3扫描组件包含和排除include,exclude
<context:component-scan base-package="com.zhujie" use-default-filters="true">//要先将默认的筛选器改为true,先扫描所有在排除
<context:exclude-filter type="annotation" // 通过注解筛选,assignable 写的是类的名字expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<context:component-scan base-package="com" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
注意:包含和排除不能在扫描时同时出现,可以出现其中一个类型的多个
12.4Autowired自动装配,默认byType,找不到时byName,配合Qualifiler(value=“beanID”)使用指定beanID,表示自动装配beanid为指定值的对象。
不常用情况:注解写在方法上,注解作用于参数
@Autowired
@Qualifier(value = "userService")
public UserService getUserService() {
return userService;
}
注意:赋值的类需要已经交给spring管理,否则被赋值对象为默认值NULL
13.面向切面编程
13.1动态代理:
public class ProxyUtil implements InvocationHandler {
//被代理类,目标类
private MathImpl mathimpl;
public Object getProxy() {
/**
* 参数1:目标对象的类加载器
* 参数2:目标对象实现的接口
* 参数3: 代理对象如何实现目标对象的方法两种写法实现InvocationHandler,传入this
* 写法二,匿名内部类
*/
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
mathimpl.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
参数3:
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
mathimpl.getClass().getInterfaces(), new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//参数1:代理对象
//参数2:方法有的参数
return method.invoke(mathimpl,args);;
}
});
注意:所有的代理对象都继承Proxy类,实现目标对象的所有接口(接口加载),然InvocationHandle指定怎么实现目标对象的方法。
13.2AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法论,是对传
统 OOP(Object-Oriented Programming,面向对象编程)的补充。
面向对象 纵向继承机制
面向切面 横向抽取机制
13.2.1 横切关注点
从每个方法中抽取出来的同一类非核心业务。
13.2.2 切面(Aspect)
封装横切关注点信息的类,每个关注点体现为一个通知方法。
13.2.3 通知(Advice)
切面必须要完成的各个具体工作,也就是横切关注点,名字不同
13.2.4 目标(Target)
被通知的对象
13.2.5 代理(Proxy)
向目标对象应用通知之后创建的代理对象
13.2.6 连接点(Joinpoint)
横切关注点在程序代码中的具体体现,对应程序执行的某个特定位置。例如:类某个方法调用前、调用后、方法捕获到异常后等。
案例
@Component
public class MathImpl implements MathI {
public int add(int i, int j) {
System.out.println("i am run");
return i+j;
}
public int sub(int i, int j) {
return i-j;
}
public int mul(int i, int j) {
return i*j;
}
public int div(int i, int j) {
return i/j;
}
}
@Component//注意要注入springIOC
@Aspect//标注当前类为切面类
public class MyLogger {
//前置通知
@Before(value = "execution(public int com.aspect.MathImpl.add(int ,int ))")//before将方法定为前置通知,value指定切入点表达式
public void before() {
System.out.println("before");
}
@After(value = "execution(public int com.aspect.MathImpl.add(int ,int ))")//after将方法定为后置通知,value指定切入点表达式
public void after() {
System.out.println("after");
}
}
注意:切面编程涉及的类都要交给spring管理,才能实现功能
13.2.7通知及切入点表达式写法扩展(占位符*):
@After(value = "execution(public int com.aspect.MathImpl.*(int ,int ))")//通知会作用到所有的带两个int参数的方法
@After(value = "execution(* com.aspect.MathImpl.*(int ,int ))")//任意返回值类型
@After(value = "execution(public int com.aspect.*.*(..))")//aspect包下任意类,..为任意参数列表
@AfterReturning返回通知
@AfterReturning(value = "execution(public int com.aspect.MathImpl.add(int ,int ))",returning = "obj")//before将方法定为前置通知,value指定切入点表达式
public void returning(Object obj) {
System.out.println("return");
}
//renturing可以接受返回值,必须设置与参数相同的名字如此段代码中的obj
@AfterThrowing异常通知
@AfterThrowing(value = "execution(public int com.aspect.MathImpl.add(int ,int ))",throwing = "ex")//before将方法定为前置通知,value指定切入点表达式
public void throwing(Exception ex) {
System.out.println("exception");
}
@Around环绕通知
@Around(value = "execution(public int com.aspect.MathImpl.add(int ,int ))")//before将方法定为前置通知,value指定切入点表达式
public Object throwing(ProceedingJoinPoint point ) throws Throwable {
Object result = null;
try {
result = point.proceed();//原方法有返回值,为保持一致接受返回值返回
}
catch(Exception e) {
e.printStackTrace();
}
finally {
System.out.println("最后!");
return result;
}
}
13.8
@Pointcut:公共切入点
@Pointcut(value="execution(public int com.aspect.MathImpl.add(int ,int ))")
public void test() {}
@Before(value = "test()"//为公共切入点的test)
public void before() {
System.out.println("before");
}
//定义PointCut后,调用通知的切入点表达式可以采用公共切入点即可访问到接入点位置
@Order(指定加载优先级)正整数,数越小优先级越高1优先级>100,默认值为int最大值
14.使用xml配置切面
@Component
public class MyLoggerXml {
public void before() {
System.out.println("beforexml");
}
}
<aop:config>
<aop:aspect ref="myLoggerXml">
<aop:before method="before" pointcut="execution(public int com.aspect.MathImpl.add(int ,int ))"/>
</aop:aspect>
</aop:config>
写法2:
<aop:config>
<aop:pointcut id="cut" expression="execution(public int com.aspect.MathImpl.add(int ,int ))"/>
<aop:aspect ref="myLoggerXml">
<aop:before method="before" pointcut-ref="cut"/>
</aop:aspect>
</aop:config>
15.事务管理
15.1首先要配置事务管理器,和配置事务注解
<!-- 创建数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 通过数据源配置JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 配置事务管理器 -->
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 开启注解驱动,即对事务相关的注解进行扫描,解析含义并执行功能 -->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager"/>
15.2@Transactional (属性)在方法上使用只对方法有效果,在类上对类中的所有方法起作用,当类上和方法上都有时就近原则
属性:
propagation:A方法和B方法都有事务,当A在调用B时,会将A中的事务传播给B方法,B方法对于事务的处理方式就是事务的传播行为
Propagation.REQUIRED:必须使用调用者的事务
Propagation.REQUIRES_NEW:将调用者的事务挂起,不使用调用者的事务,使用新的事务进行处理
isolation:事务的隔离级别,在并发的情况下,操作数据的一种规定
读未提交:脏读(事务没有提交,若发生回滚则读取了脏数据) 1
读已提交:不可重复读(读后,事务提交后数据变化不能重现上一次的结果) 2
可重复读:幻读(读取数据时,又提交新的数据,读取表中数据不一样)4
串行化:性能低,消耗大 8
数字表示法:2的次方代表权限
timeout:在事务强制回滚前最多可以执行(等待)的时间,超时则强制回滚
readOnly:指定当前事务中的一系列的操作是否为只读。若设置为只读,不管事务中有没有写的操作,mysql都会在请求访问数据的时候,不加锁,提高性能但是如果有写操作的情况,建议一定不能设置只读
rollbackFor|rollbackForClassName|noRollbackFor|noRollbackForClassName:设置事务回滚的条件
15.2事务的传播行为
A方法和B方法都有事务,A调用B时A的事务会传播,Propagation:REQUIRED必须使用调用者的事务,Propagation:REQUIRE_NEW启动新事务处理
15.3xml配置事务
<bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:advice id="tx" transaction-manager="dataSourceTransactionManager">
<tx:attributes>
<!-- 在设置好的切入点表达式下再次进行事务设置 -->
<tx:method name="buyBook"/>
<tx:method name="checkOut"/>
<!-- 只有select开头的方法才会被事务处理 -->
<tx:method name="select*" read-only="true"/>
<tx:method name="insert*"/>
<tx:method name="update*"/>
<tx:method name="delete*"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<!-- 配置切入点表达式 具体方法在tx中配置-->
<aop:config>
<aop:pointcut expression="execution(* com.atguigu.book_xml.service.impl.*.*(..))" id="pointCut"/>
<aop:advisor advice-ref="tx" pointcut-ref="pointCut"/>
</aop:config>
本文档为学习基础所写目的是为了记录以便复习,难免存在很多不足和错误,请批评指正。
参考资料:
https://www.jianshu.com/p/d96197139b5b
尚硅谷视频教程及文档