结果&问题:静态代理虽然保证了业务类只需关注逻辑本身,代理对象的一个接口只服务于一种类型的对象。如果要代理的方法很多,势必要为每一种方法都进行代理。同时如果增加一个方法,除了实现类需要实现这个方法外,所有的代理类也要实现此方法。增加了代码的维护成本。——解决:使用动态代理
3)动态代理
动态代理类的源码是在程序运行期间,通过 JVM 反射等机制动态生成。代理类和委托类的关系是运行时才确定。
定义动态代理工厂类,定义目标对象属性并通过构造方法注入值,定义方法返回代理后的对象
* 动态代理:
* 代理工厂,给多个目标对象生成代理对象!
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
public Object getProxyInstance() {
Object proxy = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
......
System.out.println("开启事务...");
result = method.invoke(target, args);
System.out.println("提交事务...");
......
return proxy;
IUserDao proxy=(IUserDao)new ProxyFactory(target).getProxyInstance();
class $jdkProxy implements IUserDao{}
注意:使用 JDK 生成的动态代理的前提是目标类必须有实现的接口。但如果某个类没有实现接口,就不能使用 JDK 动态代理。——解决:CGLIB 代理
CGLIB 是以动态生成的子类继承目标的方式实现,在运行期动态的在内存中构建一个子类,但CGLIB 使用的前提是目标类不能为 final 修饰。因为 final 修饰的类不能被继承。
3.如何使用AOP
面向切面编程,核心原理是使用动态代理模式在方法执行前后或出现异常时加入相关逻辑。
在Spring框架中底层已经集成了JDK 代理和 CGLIB 代理两种动态代理,无需自己去实现动态生成代理。
@SuppressWarnings("serial")
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
if (targetClass.isInterface(
) || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
return new ObjenesisCglibAopProxy(config);
else {
return new JdkDynamicAopProxy(config);
。。。。。。。。
完成:将内容切入到目标方法执行前后
<bean id="tsa" class="com.zuxia.aop.TransactionAop" />
<aop:config>
<aop:pointcut expression="execution(* com.zuxia.dao.impl.*.*(..))" id="pc"/>
<aop:aspect ref="tsa">
<aop:before method="beginTransaction" pointcut-ref="pc" />
<aop:after method="commit" pointcut-ref="pc"/>
<aop:around method="arroud" pointcut-ref="pc"/>
<aop:after-returning method="afterReturing" pointcut-ref="pc"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
3、Spring对持久层封装和事务管理
1.Spring如何连接数据库
在Spring中提供了对数据源(DataSource)的支持
2.Spring对数据源的管理
导入数据源相关的jar包
在Spring容器中配置一个数据源(DriverManagerDataSource)即可
3.Spring对JDBC的封装
提供了对JdbcTemplete的支持
提供了update(sql)方法实现数据的曾删改操作
提供了queryForXXX(sql)方法实现数据的查询操作
完成:对用户数据的曾删改查操作
4.事务管理
Spring提供编程式的事务管理与声明式的事务管理。
编程式的事务管理:
private DataSourceTransactionManager transactionManager;
private DefaultTransactionDefinition def;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
jdbcTemplate = new JdbcTemplate(dataSource);
transactionManager = new DataSourceTransactionManager(dataSource);
def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
public void insertUser(UserInfo user) {
TransactionStatus status = transactionManager.getTransaction(def);
try {
jdbcTemplate.update("insert into userinfo values(0,?,?,?)",user.getName(),user.getPwd(),user.getRemark());
jdbcTemplate.update("inset into userinfo values(0,?,?,?)",user.getName(),user.getPwd(),user.getRemark());
transactionManager.commit(status);
} catch(DataAccessException e) {
transactionManager.rollback(status);
System.out.println("执行异常:"+e.getMessage());
声明式的事务管理:
<!-- 声明式事务配置 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="ds"/>
</bean>
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.zuxia.dao.impl.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="
pc"/>
</aop:config>
3.如何使用接口编程
定义dao的接口类,定义数据的增删改查等方法(没有实现)
定义dao的接口实现类,实现接口中的所有方法,完成数据的持久化操作
在controller类中定义dao的接口类属性并注入实现类对象,访问方法中使用该接口属性调用方法
在Spring容器中创建dao的实现类对象,在web.xml中配置监听器并加载spring容器
4、Log4j 基本操作
1.什么是Log4j
Log4j ——日记记录工具;由Apache组织开发。
2.为什么需要使用log4j
a) 监视代码运行情况;帮助进行统计分析系统运行情况(工作是否正常)。
b) 追踪代码运行轨迹。(运行的详细信息)
c) 调试程序异常。
3.如何使用log4j
3.1 导入log4j所需的依赖。(slf4j-api、slf4j-log4j12)
3.2 在src目录下编写log4j的配置文件。文件名必须是:log4j.properties
##########配置log4j的核心控制
#语法:log4j.rootLogger=日志的输出级别,输出源名称,...
# 输出级别:由低到高
# all(打开所有日志记录)、
# trace、
# debug(记录调试信息)、
# info(记录普通信息)、
# warn(记录警告信息)、
# error(记录错误信息)、
# fatal(记录严重的错误信息)、
# off(关闭所有日志信息)
# 输出源名称:自定义即可
log4j.rootLogger=all,location1,locafile,dailyFile
##########配置 向 输出源 以 形式 输出日志信息
# 输出源:ConsoleAppender(控制台输出)、FileAppender(文件中输出)、DailyRollingFileAppender(每天向一个文件中输出)
# 形式:PatternLayout(文本)、HTMLLayout(网页)
#配置 向 控制台 以 文本 输出日志信息(System.out.println('');)
#配置输出源
log4j.appender.location1=org.apache.log4j.ConsoleAppender
#指定目标位置
log4j.appender.location1.Target=System.out
#配置输出形式
log4j.appender.location1.layout=org.apache.log4j.PatternLayout
#指定输出格式 %p表示输出级别、%d表示日期时间、%m表示记录的内容、%l表示记录内容所在位置、%n表示换行
log4j.appender.location1.layout.ConversionPattern=%p %d{yyyy-MM-dd HH:mm:ss} %m %l %n
log4j.appender.locafile=org.apache.log4j.FileAppender
log4j.appender.locafile.File=c:/test.html
log4j.appender.locafile.layout=org.apache.log4j.HTMLLayout
log4j.appender.locafile.layout.ConversionPattern=%p %d{yyyy-MM-dd HH:mm:ss.S} %m %l %n
#文件中(每天一个日志文件)
log4j.appender.dailyFile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.dailyFile.File=c:/dytest.html
log4j.appender.dailyFile.layout=org.apache.log4j.HTMLLayout
log4j.appender.dailyFile.DatePattern='.'yyyyMMdd'.html'
log4j.appender.dailyFile.layout.ConversionPattern=%p %d{yyyy-MM-dd HH:mm:ss.S} %m %l %n
3.3 程序中记录日志信息
//log4j方式
private static Logger log=Logger.getLogger(Class);
//slf4j方式
private static Logger log = LoggerFactory.getLogger(Class);
4.slf4j与log4j的区别
1)slf4j是java的一个日志门面,实现了日志框架一些通用的api,而log4j是具体的日志框架。
2)slf4j日志输出时可以使用{}占位符,而log4j只能拼接。
package com.zuxia.entity;
public class ClassInfo {
private int cid;
private String cname;
public int getCid() {
return cid;
public void setCid(int cid) {
this.cid = cid;
public String getCname() {
return cname;
public void setCname(String cname) {
this.cname = cname;
public ClassInfo(int cid, String cname) {
super();
this.cid = cid;
this.cname = cname;
public ClassInfo() {
super();
package com.zuxia.entity;
public class StudentInfo {
private int sid;
private int cid;
private ClassInfo cinfo;
private String sname;
private int age;
private String spwd;
public int getSid() {
return sid;
public void setSid(int sid) {
this.sid = sid;
public int getCid() {
return cid;
public void setCid(int cid) {
this.cid = cid;
public ClassInfo getCinfo() {
return cinfo;
public void setCinfo(ClassInfo cinfo) {
this.cinfo = cinfo;
public String getSname() {
return sname;
public void setSname(String sname) {
this.sname = sname;
public int getAge() {
return age;
public void setAge(int age) {
this.age = age;
public String getSpwd() {
return spwd;
public void setSpwd(String spwd) {
this.spwd = spwd;
public StudentInfo(int sid, int cid, ClassInfo cinfo, String sname, int age, String spwd) {
super();
this.sid = sid;
this.cid = cid;
this.cinfo = cinfo;
this.sname = sname;
this.age = age;
this.spwd = spwd;
public StudentInfo() {
super();
servie接口
package com.zuxia.service;
import java.util.List;
import com.zuxia.entity.StudentInfo;
public interface IStudentService {
List<StudentInfo> findStu();
boolean removeStu(String ids);
servlce实现类
package com.zuxia.service.impl;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.
springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import com.zuxia.dao.IStudentDao;
import com.zuxia.dao.impl.StudentDaoImpl;
import com.zuxia.entity.StudentInfo;
import com.zuxia.service.IStudentService;
@Service("stuService")
@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED)
public class StudentServiceImpl implements IStudentService {
private static Logger log=LoggerFactory.getLogger(StudentDaoImpl.class);
@Autowired
@Qualifier("stuDao")
private IStudentDao istuDao;
@Override
@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)
public List<StudentInfo> findStu() {
log.info("查询用户数据");
return istuDao.selectStu();
@Override
public boolean removeStu(String ids) {
log.info("删除用户信息,编号为:{}",ids);
String[] strIds = ids.split(",");
int count=0;
for(String tid : strIds){
count += istuDao.deleteById(Integer.parseInt(tid));
log.warn("执行结果:{}",count);
if(count==strIds.length){
log.info("执行成功...............");
return true;
log.error("执行失败,回滚事务...............");
throw new RuntimeException("删除失败");
dao层接口
package com.zuxia.dao;
import java.util.List;
import com.zuxia.entity.StudentInfo;
public interface IStudentDao {
List<StudentInfo> selectStu();
int deleteById(int id);
dao实现类
package com.zuxia.dao.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import com.zuxia.dao.IStudentDao;
import com.zuxia.entity.ClassInfo;
import com.zuxia.entity.StudentInfo;
* Dao类:数据访问层在(数据持久化操作)
@Repository("stuDao")
public class StudentDaoImpl extends JdbcTemplate implements IStudentDao {
@Autowired
@Qualifier("dds")
public void setDataSource(DataSource dataSource) {
super.setDataSource(dataSource);
@Override
public List<StudentInfo> selectStu() {
return super.query("select si.*,cname from studentinfo si inner join classinfo ci on si.cid=ci.cid", new RowMapper<StudentInfo>() {
@Override
public StudentInfo
mapRow(ResultSet rs, int rowNum) throws SQLException {
ClassInfo cinfo=new ClassInfo();
cinfo.setCname(rs.getString("cname"));
StudentInfo stu=new StudentInfo(rs.getInt("sid"), rs.getInt("cid"), cinfo, rs.getString("sname"), rs.getInt("age"), rs.getString("spwd"));
return stu;
});
@Override
public int deleteById(int id) {
return super.update("delete from studentinfo where sid=?", id);
controller
package com.zuxia.controller;
import java.util.List;
import javax.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.HiddenHttpMethodFilter;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.ModelAndView;
import com.zuxia.entity.StudentInfo;
import com.zuxia.service.IStudentService;
@Controller
@RequestMapping(value="/stuC")
public class StudentController {
private static Logger log=LoggerFactory.getLogger(StudentController.class);
@Resource(name="stuService")
private IStudentService istuService;
@GetMapping(value="/showStu")
public ModelAndView showStu(){
List<StudentInfo> slist = istuService.findStu();
log.info("查询展示,数据共{}条",slist.size());
ModelAndView mav=new ModelAndView("show");
mav.addObject("slist", slist);
return mav;
@DeleteMapping(value="/removeStu")
public String removeStu(String ids){
boolean flag = false;
try {
flag = istuService.removeStu(ids);
} catch (Exception e) {
System.out.println(e.getMessage());
log.warn("异常:{}",e.getMessage());
if(flag){
return "redirect:/stuC/showStu";
return "fail";
spring配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:property-placeholder location="classpath:jdbc.properties"/>
<bean id="dds" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${uname}" />
<property name="password" value="${upwd}" />
<property name="url" value="${url}" />
<property name="driverClassName" value="${drvierClass}" />
</bean>
<context:component-scan base-package="com.zuxia.dao" />
<context:component-scan base-package="com.zuxia.service" />
<bean id="dstm" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dds" />
</bean>
<tx:annotation-driven transaction-manager="dstm"/>
</beans>
spring-mvc配置文件
<?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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.zuxia.controller" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<mvc:annotation-driven />
<mvc:resources location="/css/" mapping="/css/**" />
<mvc:resources location="/js/" mapping="/js/**" />
<mvc:default-servlet-handler/>
</beans>
jdbc.properties配置文件
uname=root
upwd=123456
url=jdbc:mysql://localhost:3306/studb?characterEncoding=utf8
drvierClass=com.mysql.jdbc.Driver
log4j.properties配置文件
#配置log4j核心控制
log4j.rootLogger=debug,loca1
#配置具体的输入位置及格式等信息
#log4j.appender.loca1=org.apache.log4j.ConsoleAppender
#log4j.appender.loca1.Target=System.out
#log4j.appender.loca1.layout=org.apache.log4j.PatternLayout
#log4j.appender.loca1.layout.ConversionPattern=%p %d{yyyy-MM-dd HH:mm:ss} %m %l %n
log4j.appender.loca1=org.apache.log4j.DailyRollingFileAppender
#log4j.appender.loca1.File=c:/my.log
#log4j.appender.loca1.layout=org.apache.log4j.PatternLayout
log4j.appender.loca1.File=c:/my.html
log4j.appender.loca1.layout=org.apache.log4j.HTMLLayout
log4j.appender.loca1.DatePattern='.'yyyyMMdd'.html'
log4j.appender.loca1.layout.ConversionPattern=%p %d{yyyy-MM-dd HH:mm:ss} %m %l %n
Spring框架1、Spring基础1.什么是Spring定义:Spring是对现有的J2EE思想进行的扩展,使其发展成更高效、全面、开放的一套开发框架,目的减低程序之间的耦合度,简化了开发流程。特点: 采用低侵入式设计(低耦合),降低代码的污染 采用接口式编程 集中解决了历史遗留的相关问题(如:事务处理)核心:控制反转(IOC)、依赖注入(DI)、面向切面编程(AOP)2.什么是IOC思考:目前创建对象的方式? A 通过new调用构造方法创建对象 B 通过工厂设计模
我们从一个简单的容器开始,一步步的重构,最后实现一个基本的Spring框架的雏形,为了帮助我们更加深入的理解Spring的IoC的原理和源码。
详细内容见博文:
【SSH进阶之路】一步步重构容器实现Spring框架——从一个简单的容器开始(八)
【SSH进阶之路】一步步重构容器实现Spring框架——解决容器对组件的“侵入式”管理的两种方案--服务定位器和IoC容器(九)
【SSH进阶之路】一步步重构容器实现Spring框架——配置文件+反射实现IoC容器(十)
【SSH进阶之路】一步步重构容器实现Spring框架——彻底封装,实现简单灵活的Spring框架(十一)
ApplicationContext ac = new FileSystemXmlApplicationContext("applicationContext.xml");
ac.getBean("userService");
//比如:在application.xml中配置:
<bean id="userService" class="com.cloud.service.impl.UserServiceImpl">&
* 1:如果bean实现了 BeanNameAware接口,则调用BeanNameAware.setBeanName()
* 2:如果bean实现了BeanFactoryAware接口,则调用BeanFactoryAware.setBeanFactory()
* 3:如果bean实现了ApplicationContextAware接口,则调用ApplicationContextAware.se.
其中最核心的包括3个组件:Context、Bean、Core。
Bean:是spring中绝对的主角,spring失去了Bean,就像舞台上没有了演员一样。因为spring解决了一个非常关键的问题:将对象之间的依赖关系用配置文件来管理,即依赖注入机制。spring就是通过把对象包裹在Bean中从而管理这些对象的。
Context:它存在的目的就是被Bean中的数据提供生存环境。他需要发现Bean之间的关系,建立并且维护好这种关系,这个B...
本次使用的源码Spring4.3.x,JDK8,gradle4.10.2,idea2018.2.5
Spring源码使用的是Gradle 进行构建的,所以需要下载 Gradle 以及搭建 java开发环境
Java环境使用的是JDK1.8
spring-framework-4.3.x.zip 包:查看build.gradle文件 查询gradlew 有推荐匹配的gradle版本号
Spring源码下载地址:Spring源码下载