Open-source framework, starts from 2003, light-weight, full-stack.
-
AOP: 面向切面,扩展功能不是修改源代码实现。
-
IOC (控制反转), 比如有一个类,在类里面有方法(不是静态方法),调用类里面的方法,使用对象调用方法,创建类对象过程,需要new出来对象 把对象的创间不是通过new方法实现,而是交给spring配置创建类对象。
- spring, provides all layers solutions.
-
Web layer: springMVC
-
service layer: IoC of Spring
-
dao layer: jdbcTemplate of Spring
*ioc的配置文件
*ioc的注解方式
使用技术:1. xml配置文件; 2. dom4j解析xml; 3. 工厂的设计模式; 4. 反射技术
Code 原理
public class User{
public void add() {
.....
}
}
// Call method - old way
/*
在servlet中调用User类里面的内容,如果类名和方法发生改变,需要改变的东西太多。
耦合度太高了。
*/
User user = new User();
user.add();
public class UserService {
public void add() {
}
}
public class UserServlet{
UserService userService = UserFactory.getService();
userService.add();
}
// Solution: create factory class.
public class UserFactory{
// provide one method returns UserService object.
public static UserService getService() {
return new UserService();
}
}
思想: 高内聚,低耦合
public class UserService{
}
public class UserServlet {
// get object UserService
UserFactory.getService();
}
/**
Step 1. Create xml file, configure to class you want to create.
<bean id="userService" class="com.liyiandxuegang.package.UserService" />
Step 2. Create one Factory class, use dom4j to parse configuration file + reflection tech.
public class UserFactory{
// return UserService
public static UserService getService() {
// 1. Use dom4j parse xml file.
// According to id value, get the class property value responding to the id.
String classValue = "from xml class property value";
// 2. Use reflection create object
Class clazz = Class.forName(classValue);
// 3. Use reflection create object
UserService userService = clazz.newInstance();
return userService;
}
}
*/
-
Step 1. Import jar files
(1) Release.jar, javadoc.jar, sources.jar
(2) Basic jars: Beans, Core, Context, SpEL (Core container)
(3) Import logging.jar
-
Step 2. Create class and method inside of class.
-
Step 3. create spring xml file, configure the class
-
Spring core configuration name and location is not fixed. But better under /src.
-
引入约束 schema
-
Configure the class
-
-
Step 4. Create test.
@Test
public void testUser() {
//1. load configuration file
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
//2. Get object
User user = (User) applicationContext.getBean("user");
//3. Test
user.add();
}
- Bean 实例化方式
-
在spring里面通过配置文件创建对象
-
bean实例化三种方式:
-
使用类的无参构造函数
-
使用静态工厂创建
在类中创建静态方法,返回类对象
<bean id="bean2" class="com.liyiandxuegang.bean.Bean2Factory" factory-method="getBean2" /> public class Bean2 { public void add() { System.out.println("Bean 2 ------ Add"); } } public class Bean2Factory { // static method public static Bean2 getBean2() { return new Bean2(); } } @Test public void testStaticFactory() { // load ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml"); Bean2 bean2 = (Bean2) applicationContext.getBean("bean2"); bean2.add(); }
-
使用实例工厂创建()
创建一个不是静态的方法,,返回类的对象
<!-- Create factory object --> <bean id="bean3Factory" class="com.liyiandxuegang.bean.Bean3Factory" /> <bean id="bean3" factory-bean="bean3Factory" factory-method="getBean3" />
-
id (name can be anything)
-
class: class qualified path
-
name: same as id, but id can't have special chars.
-
scope: singleton(default), prototype, request, session, globalSession: (ssl)
- 有参构造函数
public class User{ private String name; public User(String name) { this.name = name; } } User user = new User("abcde");
- 使用set方法注入
public class User{ private String name; public void setName(String name) { this.name = name; } } User user = new User(); user.setName("abcde");
- 使用接口的方法
public interface Dao { public void assignVal(String name); } public class DaoImpl implements Dao { private String name; public void assignVal(String name) { this.name = name; } }
- set method(*)
<!-- Use set method to inject property value --> <bean id="book" class="com.liyiandxuegang.property.Book"> <!-- set value --> <property name="bookName" value="Test Value 2" /> </bean>
- Constructor method
// bean.xml <!-- Use constructor to inject property value --> <bean id="propertyDemo1" class="com.liyiandxuegang.property.PropertyDemo1"> <!-- Inject value --> <constructor-arg name="userName" value="Test Value" /> </bean> // PropertyDemo1.java public class PropertyDemo1 { private String userName; public PropertyDemo1(String userName) { this.userName = userName; } public void test1() { System.out.println("demo1--------test1()-------" + userName); } } // TestIoC.java @Test public void testDemo1() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml"); PropertyDemo1 propertyDemo1 = (PropertyDemo1) applicationContext.getBean("propertyDemo1"); propertyDemo1.test1(); }
###注入对象类型的属性
- Create class (Servcie and Dao)
-
在Service里面把dao作为类型属性;
-
生成dao类型属性的set方法
//1. Define a UserDao field private UserDao userDao; //2. generate setmethod public void setUserDao(UserDao userDao) { this.userDao = userDao; }
- 在配置文件中完成这个关系
<!-- 注入对象类型的属性 --> <!-- 1. 配置Service和Dao的对象 --> <bean id="userDao" class="com.liyiandxuegang.ioc.UserDao" /> <bean id="userService" class="com.liyiandxuegang.ioc.UserService"> <!-- Inject dao obj name: service类里面属性的名称 ref: dao配置bean标签的id值 --> <property name="userDao" ref="userDao"></property> </bean>
- Test
@Test public void testUserService() { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); userService.addService(); }
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- Use P namespace inject --> <bean id="person" class="com.liyiandxuegang.property.Person" p:pname="Name Value" />
- Array, List, Map, Properties
<!-- Inject complicated data value --> <bean id="personComplicated" class="com.liyiandxuegang.property.Person"> <!-- array --> <property name="arraysStrings"> <list> <value>Eric</value> <value>Mike</value> <value>Jim</value> </list> </property> <property name="list"> <list> <value>Eric List</value> <value>Mike List</value> <value>Jim List</value> </list> </property> <property name="map"> <map> <entry key="aa" value="Eric aa" /> <entry key="bb" value="Mike BB" /> </map> </property> <property name="properties"> <props> <prop key="driverClass">com.mysql.jdbc.Driver</prop> <prop key="username">root</prop> </props> </property> </bean>
IOC:控制反转,把对象创建交个spring进行配置。
DI:依赖注入,向类中属性,设置属性值。
关系: 依赖注入不能单独存在,需要在IOC基础上完成操作。
- Loading spring configuration file use lots of resources.???
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean1.xml");
##Solution?
把加载配置文件和创建对象过程,在服务器启动时候完成。
-
ServletContext Object
-
Listener Object
-
在服务器启动时,为每个项目创建ServletContext对象,
-
在ServletContext对象创建时,使用监听器可以监听到ServletContext对象在创建
-
使用监听器听到ServletContext对象创建时,加载spring的配置文件,把配置文件配置对象创建。
-
把创建出来的对象方法ServletContext的域对象里面
-
获取对象时,到ServletContext域得到
-
-
代码里特殊的标记,使用注解也可以完成一些功能。
-
注解写法:@注解名称(属性名称=属性值)
-
注解可以使用在类上面,方法上面和属性上面
-
import spring-aop.jar
-
Configure xml
<!-- define the package to scan -->
<context:component-scan base-package="com.liyiandxuegang.anno" />
Then add @annotation above the class or field, or function
@Component(value="user") // <bean id="user" class="" />
public class User {
public void annoAdd() {
System.out.println("anno Add....");
}
}
There are four annotations in Spring:
-
@Component [as component]
-
@Controller [Web]
-
@Service [Service]
-
@Repository: [Persistence]
功能相同,都是用来创建对象,用来将来对功能的扩展。
###但是控制类的作用范围:scope
@Component(value="user") // <bean id="user" class="" />
@Scope(value="prototype")
public class User {
public void annoAdd() {
System.out.println("anno Add....");
}
}
- Create class obj
Create UserDao and UserService obje
@Component(value="userDao")
public class UserDao {
public void add() {
System.out.println("dao........add");
}
}
@Service(value="userService")
public class UserService {
// define the field of userDao
@Autowired //自动注入的方法,找类的名字来注入类属性 (1)
private UserDao userDao;
// Resource second way: but this time, the value of name should be the same as the objects.
@Resource(name="userDao2")
private UserDao2 userDao2;
public void add() {
System.out.println("Service.add ========");
userDao.add();
}
}
Use @Resource should be good.
-
创建对象操作使用配置文件方式实现;
-
注入属性的操作使用注解方式实现。
Suppose, we have three classes, BookService, BookDao.class, OrdersDao.class
In xml file,
<context:component-scan base-package="com.liyiandxuegang.xmlanno" />
<bean id="bookService" class="com.liyiandxuegang.xmlanno.BookService" /> <!--BookService bookService
<bean id="ordersDao" class="com.liyiandxuegang.xmlanno.OrdersDao" /> <!--OrdersDao ordersDao-->
<bean id="bookDao" class="com.liyiandxuegang.xmlanno.BookDao" /> <!--BookDao bookDao-->
In BookService.java file
public class BookService {
@Resource(name="bookDao")
private BookDao bookDao;
@Resource(name="ordersDao")
private OrdersDao ordersDao;
public void add() {
System.out.println("bookService ..... add");
bookDao.book();
ordersDao.order();
}
}
Then, we can test it, use the Bean to create the class.
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean3.xml");
BookService bookService = (BookService)applicationContext.getBean("bookService");
public class User{
// Add user
public void add(User user) {
// code ...
}
}
// extends the function
// add user, then add logging function.
纵向体系的问题:比如父类方法名称发生了变化,在子类调用的方法也需要变化。
底层使用:动态代理方式实现
- One way (with inteface)
public interface Dao{
public void add();
}
[使用动态代理方式,创建接口实现代理对象]
public class DaoImpl implements Dao{
public void add() {
// code ....
}
}
// 增强add方法,创建和DaoImpl类平级对象,这个对象不是真正的对象,代理对象实现和DaoImpl相同的功能。
// Use JDK dynamic proxy.
- Second way (without interface) 使用cglib动态代理,没有接口
// user class
public class User{
public void add() {
}
}
// 动态代理实现, 创建User类的子类的代理对象
// 在子类中也可以调用父类的方法,完成增强
-
Pointcut
-
Advice:通知或者增强
前置通知:在方法执行之前,执行
后置通知:在方法之后执行
异常通知:方法出现异常之后
最终通知:在后置之后执行
环绕通知:在方法之前和之后来执行。
- Aspect: 切面
把增强应用到具体的方法上,这个过程称为切面。
// Basic class
public class User{
public void add() {}
public void update() {}
public void delete() {}
public void findAll() {}
}
// 连接点Jointpoint:类里面那些方法可以被增强,这些方法称为连接点。
// 切入点Aspectpoint:在类里面可以有很多的方法增强,比如实际操作中,只是增强了类中add方法和update方法,实际增强的方法称为切入点。
// Advice: 通知或者增强
- 在spring里面进行AOP操作,使用AspectJ介绍
Spring 2.0, add AspectJ plugin.
- 使用aspectJ实现AOP操作,有两种方式:
*基于AspectJ的xml配置方式
*基于AspectJ的注解方式
-
Import basic jars, and import aop jars,
-
Create spring xml, import aop schema.
Use Expression to configuration aspect point.
Mainly used expressions:
-
execution(public|private|* com.liyiandxuegang.aop.Book.add(..))
-
execution(* com.liyiandxuegang.aop.Book.*(..))
-
execution(* .(...))
execution( save*(..)): the methods with save starting.
How to configure? Read the following code:
<!-- 配置对象 -->
<bean id="book" class="com.liyiandxuegang.aop.Book" />
<bean id="myBook" class="com.liyiandxuegang.aop.MyBook" />
<!-- 配置aop操作 -->
<aop:config>
<!-- 1. 配置切入点 -->
<aop:pointcut expression="execution(* com.liyiandxuegang.aop.Book.*(..))" id="pointcut1" />
<!-- 2. 配置切面
把增强用到方法上
-->
<aop:aspect ref="myBook">
<!-- 配置增强的类型
method: 增强的类中使用那个方法作为前置增强
-->
<aop:before method="before1" pointcut-ref="pointcut1" />
</aop:aspect>
</aop:config>
In the code level, we don't need to do anything different. The only thing you need to do is in the xml file.
<!-- 配置对象 -->
<bean id="bookaop" class="com.liyiandxuegang.aop.Book" />
<bean id="myBookaop" class="com.liyiandxuegang.aop.MyBook" />
<!-- 配置aop操作 -->
<aop:config>
<!-- 1. 配置切入点 -->
<aop:pointcut expression="execution(* com.liyiandxuegang.aop.Book.*(..))" id="pointcut1"></aop:pointcut>
<!-- 2. 配置切面
把增强用到方法上
-->
<aop:aspect ref="myBookaop">
<!-- 配置增强的类型
method: 增强的类中使用那个方法作为前置增强
-->
<aop:before method="before1" pointcut-ref="pointcut1"></aop:before>
<aop:after-returning method="after" pointcut-ref="pointcut1"/>
<aop:around method="around" pointcut-ref="pointcut1"/>
</aop:aspect>
</aop:config>
In around method, we need to call ProceedingJoinPoint method for function call.
-
日志的一个工具,通过log4j能够看到程序中更详细的信息。经常使用log4j查看日志
-
导入log4j的jar包
-
复制log4j的配置文件, 复制到src目录下。
- action 调用service, service调用dao, 需要使用struts2的内容。