基本概念
在沒有Spring以前,程序是經過public UserService user = new UserService()的形式,來給一個變量賦予引用值,user變量定義後就能夠直接user.xxx()的來調用方法.
在有Spring以後,能夠直接使用public UserService user的形式給來定義變量,而省略new UserService()這一部分,這部分由Spring來進行.
由Spring建立對象,稱其爲"控制反轉",Spring建立對象的過程當中,發現對象裏面還有一個成員變量須要賦值,賦值的過程稱爲"依賴注入".
控制反轉
簡稱爲IOC,英文全稱:Inversion of Control,爲何本來本身new一個對象
使用註解
告訴了Spring大佬new哪一個對象後,若是對象裏面有成員變量,還得告訴大佬,得給這個成員變量賦值,具體XML實例以下:
<bean id="mainUI" class="com.jungle.www.controller.MainUI">
<property name="jungle" ref="userService"/>
</bean>
<bean id="userService" class="com.jungle.www.service.serviceimp.UserServiceImpl">
</bean>
<!--
bean標籤,就是用來告訴Spring建立哪一個對象
"id" 指定對象名,
"class" 是類的全路徑,寫哪一個類,就會建立哪一個類的對象.
property標籤,是告訴Spring大佬,建立的對象還有成員變量須要大佬賦值
"name" 須要賦值的成員變量名,Spring給成員變量賦值時,是經過setter 方法來賦值的,因此得給成員變量弄一個setter方法
"ref"表明引用亨達代理申請www.kaifx.cn/broker/hantecglobal.html其餘bean的id名所具備的值
這裏面有兩個bean,因此建立了兩個對象,分別名叫:mainUI和userService,其中mainUI實例裏有一個叫jungle的成員變量,這個成員變量的值是引用了userService,上述的配置,等同於如下:
public void MainUI{
private jungle = new UserServiceImpl();
}
上面的例子裏的成員變量,是引用類型,也就是一個對象,那麼基本數據類型又如何解決賦值問題?集合又怎樣解決賦值問題?系統的概括以下:
屬性賦值
value注入基本類型
<bean id="mainUI" class="com.MainUI">
<property name="str" value="李白"/>
</bean>
<!--
//上面的效果,建立了com.MainUI類的名叫mainUI的實例,而且給裏面的str成員變量賦值爲 李白
public void MainUI{
private String str;
//setter方法省略
}
//下面的實例也是同理
ref 注入已有的bean
官方源碼有一句話:The name of the property, following JavaBean naming conventions,意思就是屬性的名稱,這裏就把bean標籤的id當作屬性的的名稱就好了
List\Set\Map
<property name="list">
<list>
<value>J</value>
<value>G</value>
</list>
</property>
<property name="set">
<set>
<value>1</value>
<value>2</value>
<value>3</value>
</set>
</property>
<property name="map">
<map>
<entry key="dock" value="yellow"/>
</map>
</property>
上面經過bean標籤來實例化對象時,默認採用的是無參構造來進行實例化,還有其餘幾種方法,也須要知道如下,下面總結一下:
bean的實例化
默認構造器實例化
<bean id="mainUI" class="com.jungle.com.MainUI">
效果:建立了com.jungle.com.MainUI類的名叫mainUI的實例
注意:須要com.jungle.com.MainUI類裏具備無參構造!
靜態工廠實例化
<bean id="today" class="com.jungle.com.service" factory-method="getObject"/>
效果:經過com.jungle.com.service類的名叫getObject的靜態方法,建立一個名叫today的實例
實例工廠實例化
//Factory類
public class Factory {
public Robot getRobot(){
return new Robot();
}
}
//Robot類
public class Robot {
public void say(){
System.out.println("i am a robot");
}
}
<!--XML-->
<bean id="robot" factory-bean="factory" factory-method="getRobot"/>
<bean id="factory" class="com.Factory"/>
說明:
第一個bean
id:之後讀取的時候,就是讀取這個id來獲得對象
factory-bean:指定生產者
factory-method:指定生產者所使用的方法
第二個bean:建立一個com.Factory類的叫factory的對象
//測試
public static void main( String[] args )
{
ClassPathXmlApplicationContext cpac =
new ClassPathXmlApplicationContext( "applicationContext.xml");
Robot robot = (Robot) cpac.getBean("robot");
robot.say();
}
Spring的FactoryBean接口實例化
類實現FactoryBean<T>接口,重寫getObject()和getObjectType()方法
配置XML文件,bean的實例爲getObject方法的返回值
具體實例以下所示:
//java代碼
public class Factory implements FactoryBean<User> {br/>@Override
public User getObject() throws Exception {
return new User(1,"李白","123");br/>}
@Override
public Class<?> getObjectType() {
return User.class;
}
}
//xml配置
<bean id="user" class="com.jungle.www.controller.Factory"/>
//注:在測試類中,使用getbean("user")便可獲得User的實例
當bean已經配置成功後,如何測試呢?
首先得讀取xml配置文件:
ApplicationContext context= new ClassPathXmlApplicationContext( "applicationContext.xml");
而後經過調用其方法,獲得對象:
User user = context.getBean("user", User.class)
下面總結一下基本的API吧
核心API
BeanFactory IOC容器的基本接口
ApplicationContext 擴展的IOC容器接口
ClassPathXmlApplicationContext 基於xml配置文件的IOC容器
依賴注入
英文簡稱DI
英文全稱: Dependency Inject
注入方式
setter注入
必須提供setter方法
構造器注入
注:name和index任選一項便可表明你的選擇
bean的做用域
prototype
原型 => 每次建立一個實例
singleton
單例[默認] => 一個bean的定義,只有一個實例,不是一個類只有一個實例
request
一個請求一個實例
session
一個會話一個實例
websocket
一次websocket連接一個實例
bean的生命週期
初始化和銷燬
在bean配置上寫init-method和destroy-method
實現InitializingBean和DisposableBean及其方法
在容器關閉的時候銷燬
//例:
public class Cycle2 implements InitializingBean, DisposableBean {br/>@Override
public void afterPropertiesSet() throws Exception {}
@Override
br/>System.out.println("開始....");
}
@Override
public void destroy() throws Exception {
System.out.println("結束了....");
}
}
配置方式
ps:下面的代碼實現,是在IDEA中使用Maven來進行構建和管理,不會Maven的能夠去網站:https://how2j.cn/k/idea/idea-maven-config/1353.html學習學習
方式一[純XML實現]
項目結構
APP類
public class App
{
public static void main( String[] args )
{
ClassPathXmlApplicationContext cpac =
new ClassPathXmlApplicationContext(
"applicationContext.xml");
MainUI mainUI = cpac.getBean("mainUI", MainUI.class);
mainUI.mainUI();
}
}
MianUI類
public class MainUI {
private UserService userService;
public void mainUI(){
Scanner temp = new Scanner(System.in);
while(true){
System.out.println("請輸入登陸帳號:");
String account = temp.next();
System.out.println("請輸入登陸密碼:");
String password = temp.next();
User user = userService.judgeUser(account, password);
if(null != user){
System.out.println("登陸成功");
System.exit(0);
}else{
System.out.println("帳號或密碼錯誤,請從新登陸");
}
}
}
public void setUserService(UserService userService) {
this.userService = userService;
}
}
在此類中,聲明瞭UserService類的userService變量,區別於傳統的賦值方式,這裏僅僅只是聲明瞭該變量,根據java的編程規範,未賦值的引用變量,默認值爲null.
Spring要作的,就是將userService賦值,而採用xml配置方式,是須要setter方法的,因此在最後添加了一個setUserService方法
UserServiceImpl類
public class UserServiceImpl implements UserService {
private UserDAO userDAO;br/>@Override
public User judgeUser(String account, String password) {
return userDAO.select(account,password);
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
}
代碼分析:有一個變量userDAO須要賦值
UserDAOImpl類
public class UserDAOImpl implements UserDAO {
private QueryRunner qr;br/>@Override
public User select(String account, String password) {
//創建一個解決數據庫下劃線問題的對象
BasicRowProcessor brp = new BasicRowProcessor(new GenerousBeanProcessor());
//準備sql語句,實際應用時不要用 來查詢,影響效率
String sql = "select from user where user_account=? and user_password=?";
//準備填充數據
Object[] obj = {account,password};
//進行查詢操做
User user = null;
try {
user = qr.query(sql, new BeanHandler<User>(User.class, brp),obj);
} catch (SQLException e) {
throw new RuntimeException("query異常",e);
}
return user;
}
public void setQr(QueryRunner qr) {
this.qr = qr;br/>}
}
此代碼中,有一個名叫qr的成員變量須要賦值,而這裏還執行了數據庫的查詢操做,須要在pom.xml文件中引入jar包
User類
@Data
@AllArgsConstructorbr/>@NoArgsConstructor
public class User implements Serializable {
private int UserId;
private String UserAccount;
private String UserPassword;
}
在這裏,使用了lombok來給私有的成員變量創建getter、setter方法和空參構造及有參構造
applicationContext.xml文件配置
<!--在App類中開始啓動,須要獲得MainUI類的實例-->
<!--在MainUI類中,存在有叫userService的實例,
因此properties的name表明的就是實例名,ref指引用的地址-->
<bean id="mainUI" class="com.jungle.www.controller.MainUI">
<property name="userService" ref="userService"/>
</bean>
<!--獲得UserServiceImpl的實例,UserServiceImpl的實例中存在有叫userDAO的實例-->
<bean id="userService" class="com.jungle.www.service.serviceimp.UserServiceImpl">
<property name="userDAO" ref="UserDAO"/>
</bean>
<!--UserDAOImpl的實例存在有qr的實例,因此得給qr賦值-->
<bean id="UserDAO" class="com.jungle.www.dao.daoimp.UserDAOImpl">
<property name="qr" ref="queryRunner"/>
</bean>
<!--經過構造器(
public QueryRunner(DataSource ds) {
super(ds);
})
獲得QueryRunner的實例,須要傳一個DataSouce的實例-->
<bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner">
<constructor-arg name="ds" ref="druidDataSource"/>
</bean>
<!--德魯伊鏈接池-->
<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.classDriver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.user}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!--配置文件-->
<bean id="propertySourcesPlaceholderConfigurer" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location" value="druid.properties"/>
</bean>
druid.properties文件
jdbc.classDriver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/blog?userUnicode=true&characterEncoding=utf8
jdbc.user=root
jdbc.password=root123
pom.xml文件配置
<!--數據庫_驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!--數據庫_工具包-->
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.6</version>
</dependency>
<!--數據庫_德魯伊鏈接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--Lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<!--SpringFrameWork-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
完整代碼已上傳:
連接:https://pan.baidu.com/s/1X64xcNhcqxOkr6sntraiBw
提取碼:upuc
方式二[註解]
經過註解方式能夠更加快速配置,只須要在類上面加上註解便可
註冊springbean
@Controller 加在Controller層的實現類上
@Service 加在Service層的實現類上
@Repository 加在Dao層的實現類上br/>@Component加類上,該類就會被Spring識別
自動依賴注入 @Autowired @Value
生命週期 @PostConstruct @PreDestroy
做用域範圍 @Scopebr/>方式三[java配置]
註解:
@Bean
標記某個方法返回值爲spring的bean,方法參數爲依賴注入的請求br/>@Configuration
標記一個類爲配置類 applicationContext.xmlbr/>@ComponentScan
打開包掃描功能,而且指定掃描的包 等價於 <context:component-scan base-package=「xxx」>br/>再次簡化
加入@Controller…@Autowired
@PropertySource("{配置文件位置}")
AOP
Aspect Oritented Programming AOP 面向切面編程
Object Oritened Proguramming OOP 面對對象編程
概念
具備橫切性質的系統功能,例如:日誌記錄、性能統計、事務管理、安全檢查等等。散佈在系統的各個類中。須要一種機制能將這類功能自動加入到須要的位置中去。這種機制就是AOP。
名詞
鏈接點 joinpoint 須要加入功能的位置(方法)
切入點 pointcut 執行加入功能的鏈接點,從鏈接點選出的須要加入功能的鏈接點
通知 advice 須要實現的功能
切面 aspect 切入點和通知的組合
目標對象 target 鏈接點(方法)所在的對象
織入 weave 將切面應用到目標對象的過程
步驟
1) 編寫service類
2) 編寫通知 , 實現MethodBeforeAdvice接口
//method 要執行的方法
// args 方法的參數
// target 方法所在的對象
public void before(Method method, Object[] args, Object target) throws Throwable {
}
3)配置xml
配置service
配置通知
配置切入點,class= org.springframework.aop.support.JdkRegexpMethodPointcut ,配置屬性pattern=> service的方法
配置切面,class=org.springframework.aop.support.DefaultPointcutAdvisor 鏈接切入點和通知
包裝service類, class= org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator
獲取bean,調用方法,將會看到通知執行了
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">;
<!--目標對象-->
<bean id="userService" class="com.jungle.spring.aop.service.impl.UserServiceImpl"/>
<!--通知: 實現了打日誌的功能-->
<bean id="beforeExecution" class="com.jungle.spring.aop.component.BeforeExecution"/>
<!--切入點:選出了須要增長功能的方法-->
<bean id="pointCut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value="com.jungle.spring.aop.service.impl.UserServiceImpl.addUser"/>
</bean>
<!--切面:鏈接切入點和通知,讓打日誌功能在切入點的位置執行-->
<bean id="aspect" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="pointcut" ref="pointCut"/>
<property name="advice" ref="beforeExecution"/>
</bean>
<!--包裝userService-->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
</beans>
通知類型
前置通知 : 方法執行以前 MethodBeforeAdvice
後置通知 : 方法執行以後 AfterReturningAdvice
環繞通知 : 方法執行先後 MethodInterceptor
異常通知 : 拋出異常時
最終通知 : finally執行時
注:面向接口編程 1)解耦,修改實現類 2)默認使用接口的方式生成代理
依賴
aspectj
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>
通知類型
前置通知 : 方法執行以前 MethodBeforeAdvice
後置通知 : 方法執行以後 AfterReturningAdvice
環繞通知 : 方法執行先後 MethodInterceptor
異常通知 : 拋出異常時
最終通知 : finally執行時
注:面向接口編程 1)解耦,修改實現類 2)默認使用接口的方式生成代理
依賴
aspectj
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.9</version>
</dependency>html